Windows: Kopiowanie / przenoszenie pliku z wyrażeniami regularnymi nazw plików?

10

po prostu chcę uruchomić:

C:\>xcopy [0-9]{13}\.(gif|jpg|png) s:\TargetFolder /s

wiem, xcopyże nie obsługuje wyszukiwania nazw plików wyrażeń regularnych.

nie mogę się dowiedzieć, jak sprawdzić, czy PowerShell ma Cmdletkopiować pliki; a jeśli tak, jak sprawdzić, czy obsługuje dopasowanie nazw plików wyrażeń regularnych.

Czy ktoś może pomyśleć o sposobie wykonania kopiowania / przenoszenia pliku rekurencyjnego z dopasowaniem wyrażenia regularnego?

Ian Boyd
źródło
1
należy to przenieść do stackoverflow, prawda?
user33788,
1
@smoknheap: Może być jedno i drugie, uważam, że skrypty Powershell stają się coraz bardziej narzędziem Power User. To jest raczej pytanie zastępujące xcopy niż pytanie skryptowe.
Doltknuckle

Odpowiedzi:

5

Lubię używać wszystkich poleceń Powershell, kiedy mogę. Po kilku testach jest to najlepsze, co mogę zrobić.

$source = "C:\test" 
$destination = "C:\test2" 
$filter = [regex] "^[0-9]{6}\.(jpg|gif)"

$bin = Get-ChildItem -Path $source | Where-Object {$_.Name -match $filter} 
foreach ($item in $bin) {Copy-Item -Path $item.FullName -Destination $destination}

Pierwsze trzy wiersze mają na celu ułatwienie odczytu. Możesz zdefiniować zmienne w rzeczywistych poleceniach, jeśli chcesz. Kluczem do tego przykładu kodu jest polecenie „Where-Object”, które jest filtrem, który akceptuje dopasowanie wyrażeń regularnych. Należy zauważyć, że obsługa wyrażeń regularnych jest trochę dziwna. Znalazłem tutaj kartę referencyjną PDF z obsługiwanymi znakami po lewej stronie.

[EDYTOWAĆ]

Jak wspomniano „@Johannes Rössel”, możesz również zredukować ostatnie dwie linie do jednej linii.

((Get-ChildItem -Path $source) -match $filter) | Copy-Item -Destination $destination

Główną różnicą jest to, że sposób Johannesa filtruje obiekty, a mój sposób filtruje tekst. Podczas pracy z Powershell prawie zawsze lepiej jest używać obiektów.

[EDIT2]

Jak wspomniano @smoknheap, powyższe skrypty spłaszczą strukturę folderów i umieszczą wszystkie twoje pliki w jednym folderze. Nie jestem pewien, czy istnieje przełącznik, który zachowuje strukturę folderów. Wypróbowałem przełącznik -Recurse i to nie pomaga. Jedynym sposobem, w jaki udało mi się to uruchomić, jest powrót do manipulacji ciągami i dodawanie folderów do mojego filtra.

$bin = Get-ChildItem -Path $source -Recurse | Where-Object {($_.Name -match $filter) -or ($_.PSIsContainer)}
foreach ($item in $bin) {
    Copy-Item -Path $item.FullName -Destination $item.FullName.ToString().Replace($source,$destination).Replace($item.Name,"")
    }

Jestem pewien, że jest to bardziej elegancki sposób, ale z moich testów to działa. Zbiera wszystko, a następnie filtry dla dopasowań nazw i obiektów folderów. Musiałem użyć metody ToString (), aby uzyskać dostęp do manipulacji ciągami.

[EDIT3]

Teraz, jeśli chcesz zgłosić ścieżkę, aby upewnić się, że wszystko jest poprawne. Możesz użyć polecenia „Write-Host”. Oto kod, który da ci kilka wskazówek, co się dzieje.

cls
$source = "C:\test" 
$destination = "C:\test2" 
$filter = [regex] "^[0-9]{6}\.(jpg|gif)"

$bin = Get-ChildItem -Path $source -Recurse | Where-Object {($_.Name -match $filter) -or ($_.PSIsContainer)}
foreach ($item in $bin) {
    Write-Host "
----
Obj: $item
Path: "$item.fullname"
Destination: "$item.FullName.ToString().Replace($source,$destination).Replace($item.Name,"")
    Copy-Item -Path $item.FullName -Destination $item.FullName.ToString().Replace($source,$destination).Replace($item.Name,"")
    }

Powinno to zwrócić odpowiednie ciągi. Jeśli gdzieś nic nie dostaniesz, będziesz wiedział, z którym przedmiotem masz problemy.

Mam nadzieję że to pomoże

Doltknuckle
źródło
Zauważ, że nie musisz $item.FullNametam używać - odpowiednia właściwość jest pobierana automatycznie, jeśli przekazujesz obiekt FileInfo (imho, nie powinieneś, ponieważ moc PowerShell pochodzi z przekazywania obiektów strukturalnych, a nie ciągu znaków). Co więcej, możesz umieścić wszystko w jednym potoku: ((gci $source) -match $filter) | cp -dest $destination(nieco przystosowany do zwięzłości - nie krępuj się zmieniać; mówię tylko, że nie foreachjest to konieczne).
Joey,
Podczas testowania nie mogłem poprawnie ustawić obiektów do potoku. To kolej zmusza mnie do użycia polecenia foreach. Spróbuję twojego kodu i zobaczę, co się stanie. Dzięki za zwrócenie na to uwagi.
Doltknuckle
czy ma to ten sam problem co mój, gdy spłaszcza katalog docelowy? xcopy normalnie zachowałby strukturę katalogów w katalogu docelowym, prawda?
user33788
Copy-Item : Cannot bind argument to parameter 'Path' because it is null
Ian Boyd,
Należy pamiętać, że Trimnie jest przeznaczony do usuwania ciągu z końca innego ciągu, zamiast tego usuwa wszystkie wystąpienia znaków w ciągu parametrów od początku i końca ciągu, do którego jest wywoływany. W twoim przypadku, jeśli $item.Namezawiera wielką literę C, usunie również literę dysku C z początku łańcucha.
Andris
3

PowerShell jest doskonałym narzędziem do tego zadania. Do kopiowania można użyć cmdletu Copy-Item . Możesz potokować go za pomocą innych poleceń cmdlet dla złożonych poleceń kopiowania, oto ktoś, kto dokładnie to zrobił :)

Wyrażenia regularne wykorzystują klasę .NET RegEx z przestrzeni nazw System.Text.RegularExpressions, istnieje szybki poradnik na temat tych klas

Program PowerShell ma również operatory -match i -replace, których można używać podczas potokowania z kopiowaniem elementu

Istnieją również narzędzia, które pomogą Ci stworzyć samego RegEx, np. Znajomy RegEx

armannvg
źródło
Imho -matchi -replacenależy o tym wspomnieć przed wejściem do System.Text.RegularExpressions.RegEx. Przynajmniej dla mnie rzadko używam [regex]bezpośrednio; Jednak ja nie często używać -matchi -replaceoperatorów. Jeśli chodzi o tworzenie wyrażeń regularnych, uważam, że PowerShell jest bardzo przydatny w testowaniu i dopracowywaniu wyrażeń regularnych, które piszesz.
Joey,
poprosiłem o odpowiedź na twoją odpowiedź w tym pytaniu: superuser.com/questions/149808/...
Ian Boyd
0

jako pomysł, ale potrzebuje trochę pracy

reż -r | ? {$ _ -match '[0-9] {13} \. (gif | jpg | png)'} | % {xcopy $ _. pełna nazwa c: \ temp}

użytkownik33788
źródło