PowerShell - Odczytywanie części nazwy pliku

0

Witam,
Piszę skrypt w PowerShellu do obsługi logów (można założyć że zwykłe pliki *.txt w danym folderze) i chciałbym wyselekcjonować te nazwy plików w tym folderze względem dzisiejszej daty (to zrobione). Moim wynikiem są nazwy logów z dnia: dziś. Mając tę informację chciałbym nazwy plików wyselekcjonować otrzymując tylko te, które zawierają ostatnie pięć znaków np. "th.txt".
Przykładowo mam wynik logów z dnia: dziś:

log1-222.txt
log2-333.txt
log3-th.txt
log5-322th.txt
log9-333th.tx

I chciałbym uzyskać z kolejnej modyfikacji algorytmu:

log3-th.txt
log5-322th.txt
log9-333th.txt

Przeszukałem wiele stron na ten temat i próba stosowania dot-netowych metod do wycinania fragmentów z tekstu nie działała w FOREACH. Nie chcę tego robić w C++ czy C# bo zależy mi na skrypcie gdyż można go szybko edytować i przejrzeć jego strukturę bez uruchamiania środowiska.
Mój algorytm:

$todayData = get-date
$nameOfFile= Get-ChildItem 'E:\Logi' -Filter *.txt | `
where {$_.lastWritetime.month -eq $todayData.month -AND $_.lastWritetime.day -eq $todayData.day -AND $_.lastWritetime.year -eq $todayData.year } | `
format-Table Name
$nameOfFile

To daje w wyniku nazwy plików z dzisiejszego dnia. Pomysły miałem różne i nie wychodziły, np:

$todayData = get-date
$nameOfFile= Get-ChildItem 'E:\Logi' -Filter *.txt | `
where {$_.lastWritetime.month -eq $todayData.month -AND $_.lastWritetime.day -eq $todayData.day -AND $_.lastWritetime.year -eq $todayData.year } | `
format-Table Name
$nameOfFile
foreach($item in $nameOfFile)
{
if($item.EndsWith("th.txt"))
{
$item
}
}

Ale żadnych metod nie mogę używać w pętli 'foreach'. Wynik kończy się błędami typu:

Method invocation failed because [Microsoft.PowerShell.Commands.Internal.Format.GroupStartData] doesn't contain a method named 'EndsWith'.
At G:\SecondProject\dateOfFile.ps1:8 char:18
+ if($item.EndsWith <<<< ("th.txt"))
    + CategoryInfo          : InvalidOperation: (EndsWith:String) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

Użycie przed pętlą tej samej metody na sztywnej zmiennej tak jak:

 $nazwa="blablath.txt"
$nazwa.EndsWith("th.txt")

Da wynik true.
Jak mogę to zrobić na wynikowych nazwach plików ?
Jeszcze z ciekawszych pomysłów to:
([string]$item).EndsWith("th.txt"))
Ale fragment "[string]" nie jest równoważny z rzutowaniem typu ? Bo wynik był oczywiście false z powodu takiego, że
[string]$item daje w wyniku Microsoft.PowerShell.Commands.Internal.Format.FormatStartData
Ale nie korzystając z rzutowania i pisząc $item.toString() otrzymuje ten sam wynik co rzutując. ^^

Może ktoś mi pomóc jak się uporać z tym?

1

Widzę że mamy tu ekspertów w tej dziedzinie ;D No nic, rozwiązałem ten problem wykonując rzutowanie w miejscu inicjacji, bo każdy przechwycony obiekt ma typ 'obiekt' z tego co się domyśliłem, dlatego nie mogłem używać "substring(x,y)" ani tablicowych indeksów [] do wydobywania znaków. Jak to rozwiązałem?
Błędny przykład: (wygeneruje błąd w ostatniej linii)

$nameOfFile= Get-ChildItem 'E:\Logi' -Filter *.txt | `
where {$_.lastWritetime.month -eq $todayData.month -AND $_.lastWritetime.day -eq $todayData.day -AND $_.lastWritetime.year -eq $todayData.year } | `
format-Table Name
($nameOfFile[0]).substr(0,1)

Poprawiony przykład:

[string]$nameOfFile= Get-ChildItem 'E:\Logi' -Filter *.txt | `
where {$_.lastWritetime.month -eq $todayData.month -AND $_.lastWritetime.day -eq $todayData.day -AND $_.lastWritetime.year -eq $todayData.year } | `
format-Table Name
($nameOfFile[0]).substr(0,1)

Wnioski:
Jeśli chcesz posługiwać się metodami "stringowymi" przy pierwszym użyciu zmiennej "$zmienna" zastosuj rzutowanie [string]. Np. [string]$zmienna ... w moim rozumieniu daje to taki wynik jak w C#/C++ "string zmienna="" "
Wklejam do dla przyszłych google'owiczów i skrypciarzy ^^

2

Obiecany skrypt:

$path = ".\"
# Get-Date zwraca obiekt DateTime on ma właściwość Date, ktora też jest typu DateTime ale z czasem usatwionym na 00:00:00
$date = (Get-Date).Date

# filtruje pliki do zmiennej
$files = Get-ChildItem -Path $path -Filter "*th.txt" | # według wzorca, gwiazdek może być wiecej
    where {$_.LastWriteTime.Date -eq $date} # porównanie samych daty, LastWriteTime to też typ DateTime

'formatowanie listy jako tablicy'
$files | Format-Table

'formatowanie listy jako liste własściwości'
$files | Format-List


'typy: $files'
$files.GetType() # files jest talicą obiektów...
$files[0].GetType() # ...typu IO.FileSystemInfo

'typy: $files | Format-Table'
($files | Format-Table).GetType() # files jest talicą obiektów...
($files | Format-Table)[0].GetType() # ...typu Microsoft.PowerShell.Commands.Internal.Format.StartData


'iterowanie po elementach listy'
$files | foreach {
    $_.GetType() # każdy jest typu IO.FileSystemInfo
    $_.Name # sama nazwa pliku
    $_.FullName # pełna ścieżka
    "$_" # "wklejenie" do tekstu
    [String]$_ # rzutowanie na String 
}

W twoim przykładzie tablicę FileSystemInfo zamieniałeś operacją w strumieniu | Format-Table na obudowę formatującą wyniki. Do przykładu dodałem też inny formater.

Jeżeli czaiłbyś wybrać w jednym strumieniu tylko nazwy plików to do tego służy polecenie select:

$files = Get-ChildItem -Path $path -Filter "*th.txt" |
    where {$_.LastWriteTime.Date -eq $date} |
    select -ExpandProperty Name # wybieram tylko nazwe pliku

'typy z expand property: $files'
$files.GetType() # files jest talicą obiektów...
$files[0].GetType() # ...typu String

'iterowanie po elementach listy'
$files | foreach {
    $_.GetType() # każdy jest typu String (choć mówi że object ;)
    $_ # sama nazwa pliku
}

Mimo iż PowerShell jest językiem skryptowym (dynamicznym...w znacznym stopniu też) to jednak pod maską używa .NET frameworka i jego systemu typów. Można więc szukać w MSDN informacji o funkcjach czy własnościowy obiektów np. DateTime - http://msdn.microsoft.com/en-us/library/system.datetime.aspx.

Jeszcze warto nadmienić, że w PS można używać skrótów do typów. Dokładnie pomijać przestrzeń System (np. [String]$_ jest równoważne z [System.String]$_</code>. I jeszcze jedna fajna możliwość w PS to parsowanie stringów <code>[DateTime]"2013-08-23" daje nam datę i czas w typach .NET.

Przy okazji polecam narzędzie PowerGUI (http://www.powergui.org/downloads.jspa). Jest nieco ciężkie (doży rozmiar pliku, czas ładowania) ale za to jest dopełnianie poleceń i ich argumentów, lepsze debugowanie od domyślnego narzędzia i podgląd zmiennych. Ponadto potrafi dopełniać właściwości i funkcje jeżeli zmienna posiada już jakaś wartość.

1

Dzięki za wyczerpującą odpowiedź, wiedzy nigdy nie ma za mało ;) Ludzie z Windowsem 7 (lub nowszym) mają wbudowane GUI, może mniej zaawansowane ale w pełni samodokumentowany i przy użyciu głowy i znajomości angielskiego można sobie poradzić ;) Najlepszy informatyk to leniwy informatyk, nie każdy chce pobierać coś hah, ale dzięki za poświęcenie czasu :)

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.