Jak mogę rekurencyjnie kopiować pliki według rozszerzenia, zachowując strukturę katalogów?

71

W wierszu poleceń systemu Linux chciałbym skopiować (bardzo duży) zestaw .txtplików z jednego katalogu (i jego podkatalogów) do innego.

Potrzebuję struktury katalogów, aby pozostać nienaruszona, i muszę zignorować pliki oprócz tych, które kończą się na .txt.

nieodebrany bagaż
źródło
2
Mając cp i znajdź jako tagi w swoim pytaniu, czy to oznacza, że ​​jesteś przywiązany do tych opcji? Ponieważ twój zestaw danych jest bardzo duży, warto założyć, że proces kopiowania może zostać przerwany z pewnych powodów i będziesz musiał go ponownie uruchomić. Nie jestem pewien, czy metoda find / cp będzie mogła wznowić przesyłanie i skopiować tylko brakującą część. Jeśli nie jesteś przywiązany do szukania / cp, możesz rozważyć rsync, który jest mądrzejszy. Jego opcja --exclude pozwala pominąć pliki .txt.
vtest
Uczciwe połączenie - rsync jest prawdopodobnie lepszą opcją. Nie przywiązany do znalezienia / cp. (I tak ich użyłem - rsync nie został zainstalowany na zdalnej maszynie, był to serwer sieciowy na żywo i chciałem zostawić jak najmniej śladu), jak to możliwe.
nieodebrane

Odpowiedzi:

95

Aby to zrobić, możesz użyć find i cpio

cd /top/level/to/copy
find . -name '*.txt' | cpio -pdm /path/to/destdir

(-updm for overwrite destination content.)
Cedr
źródło
Dlaczego m? myślałem, że to po prostu zachować datę modyfikacji pliku.
Mubashar
7
cd /source/path
find -type f -name \*.txt -exec install -D {} /dest/path/{} \;
sborsky
źródło
Teraz brakuje .po find. Również w systemie macOS 10.13.1 działało:find . -type f -name "*.txt" -exec install -v {} /dest/path/{} \;
ponury
2

Inne podejście

find . -name '*.txt' -exec rsync -R {} path/to/dext \;

Marc
źródło
Podoba mi się to rozwiązanie. Robiłem find . -iname '*.txt' -exec rsync -Rptgon {} path/to/dext \;dopasowanie bez rozróżniania wielkości liter oraz posiadałem uprawnienia i uprawnienia preservera.
MountainX
1

Najłatwiejszy dla mnie sposób:

cp --parents -R jobs/**/*.xml ./backup/

Jednym z haczyków jest przejście do katalogu „pożądanego”, aby „ścieżka nadrzędna” była poprawna.

Upewnij się także, że w bash włączyłeś rekurencyjne globusy:

shopt -s globstar
icyerasor
źródło
1

co powiesz najpierw na to

cp -r /old/folder /new/folder

następnie przejdź do nowego folderu i uruchom

find . -type f ! -iname "*.txt" -delete

Lub tylko

cp -r /old/folder /new/folder && find . -type f ! -iname "*.txt" -delete

Edycja: ok chcesz jedno polecenie, które filtruje (nie testowałem tego, ponieważ mój system nie ma cpiopolecenia!). Oto, gdzie go znalazłem: http://www.gnu.org/software/findutils/manual/html_mono/find.html#Copying-A-Subset-of-Files

find . -name "*.txt" -print0 |
     cpio -pmd0 /dest-dir

Proszę przetestować ten pierwszy, bo nie próbowałem jeszcze. Gdyby ktoś to zweryfikował, byłoby świetnie.

Dennis
źródło
kiwa głową Pozdrawiam - to by działało, ale bez filtrowania do .txt Patrzę na kilka milionów plików (wychodzi na kilkaset GB). W razie potrzeby być może będę musiał, ale chciałbym filtrować podczas kopiowania, jeśli to możliwe
nieodebrany bagaż
1
Pozdrawiam, edytowana wersja działa, jeśli usunę „0” z -pmd0
nieodebrany
Należy zachować 0in -pmd0i włożyć -print0do końca findpolecenia (tuż przed |).
G-Man,
1

Próbowałem zrobić to samo na macOS, ale żadna z opcji tak naprawdę nie działała dla mnie. Aż odkryłem ditto.

Musiałem skopiować wiele plików .wav i pomijać pliki wideo ... Oto co wymyśliłem:

find . -type f -iname "*.wav" -ls -exec ditto {} /destination/folder/{} \;

  • find .- Uruchamia wyszukiwanie w bieżącym folderze. upewnij się, cd /source/folderzanim zaczniesz

  • -type f - Określa tylko wyszukiwanie plików

  • -iname "*.wav" - Oznacza to, że należy rozróżnić wielkość liter * .wav
  • -ls- Pokazuje plik, nad którym pracuje. W przeciwnym razie nic nie pokazuje.
  • -exec ditto {} /destination/folder/{} \; - Wykonuje całą pracę kopiowania i tworzenia plików z tym samym drzewem katalogowym.
Benjamin McGuire
źródło
0

Przejdź do katalogu:

find . -regex '<regexp_to_get_directories_and_files_you_want>' | xargs -i cp -r --parents {} path/to/destination

Jest trochę bardziej prosty i potężny, jeśli zarządzasz wyrażeniami regularnymi.

keywalker
źródło
-1

Przejdź do katalogu:

cp '*.css' /path/to/destination

Będziesz musiał przejść do każdego folderu w katalogu, ale jest to lepsze niż większość opcji, które widziałem do tej pory.

Feniks
źródło
Ta metoda nie jest rekurencyjna, co oznacza, że ​​w przypadku dużych katalogów możesz to robić przez dłuższy czas ...
Iain Reid