Linux: Skopiuj wszystkie pliki pasujące do wzorca z katalogu i podkatalogów do jednego katalogu

31

Gdybym chciał, aby skopiować wszystkie *.sopliki srcdo dstzrobiłbym:

cp src/*.so dst

Chcę jednak skopiować wszystkie *.sopliki z src i jego podkatalogów do dst. Jakieś wskazówki?

Albus dumbledore
źródło

Odpowiedzi:

36

Próbować:

find src/ -type f | grep -i so$ | xargs -i cp {} dst
Mike Insch
źródło
17
findPotrafi dopasowywać wzorce i wykonywać polecenia. Nie trzeba przesyłać danych wyjściowych:find src/ -type f -name '*.so' -exec cp '{}' dst/ ';'
jáquer
1
Tak, może jednak, choć często łatwiej jest odczytać potok, również możliwości dopasowania wzorca grepznacznie przewyższają proste wzorce powłoki używane w -nameparametrze do find. xargsjest również znacznie potężniejszy niż -execparametr do find.
Mike Insch,
2
Rozwiązanie @jaquer jest znacznie lepsze, ponieważ na MacOSX narzędzie xargs nie ma opcji -i. Ale jego rozwiązanie działa jak urok.
bialix,
Walczyłem z komunikatem o błędzie w argumencie -i do xargs, dopóki nie przeczytałem komentarza @bialix dotyczącego rozwiązania jaquera, które działało idealnie na moim Macu. Dzięki
svannoy,
Czy utworzy to podkatalogi w razie potrzeby?
Lennart Rolland
15

Jeśli używasz Bash, możesz włączyć globstar opcję powłoki, aby rekurencyjnie dopasowywać pliki i katalogi:

shopt -s globstar
cp src/**/*.so dst

Jeśli chcesz znaleźć pliki, których nazwy zaczynają się od ., i / lub pliki w i pod katalogami, których nazwy zaczynają się od ., ustaw dotglobrównież opcję (np. Z shopt -s dotglob). Możesz ustawić je oba za pomocą jednego polecenia:

shopt -s globstar dotglob
Jáquer
źródło
Nie kopiuje plików w podkatalogach zaczynających się od. w ich imieniu
rboy
8

Wypróbowałem polecenie sugerowane przez Mike'a:

find src/ -type f | grep -i so$ | xargs -i cp {} dst

ale skończyło się to zrzuceniem wszystkich plików do katalogu dstz utratą ich ścieżek względnych.

Aby zachować ścieżki względne, polecenie należy zmodyfikować w następujący sposób:

find src/ -type f | grep -i so$ | xargs -i cp {} dst/{}
Ilya Druker
źródło
7
+1. Zakłada się jednak, że katalogi odpowiadające względnym ścieżkom źródłowym istnieją pod dst. Jeśli tak nie jest, użyj cp --parents. Pamiętaj też, aby podać nazwy plików. Zatem: ... | xargs -i cp --parents "{}" dst(zauważ, że ostatnim argumentem cpjest teraz „tylko” katalog docelowy). Polecenie może być wykonane nawet krótszy (i prawdopodobnie szybciej) przy użyciu -tflagi: ... | xargs cp --parents -t dst.
Stephan202
1
@ Stephan202 Musiałem użyć... | xargs cp {} --parents -t dst.
warvariuc
dla tych na komputerze Mac --parentsnie jest dostępny. Użyłem dittozamiast niego: stackoverflow.com/questions/11246070/cp-parents-option-on-mac
Bryan Young,
3

Kolejny sposób to zrobić:

find src/ -type f -name "*.so" -exec cp {} dst/ \;
Kyriakos
źródło
I to powinno zmniejszyć liczbę cpprocesów: ... -exec cp -t dst/ {} +.
Kamil Maciorowski
Hej Kamil! Dziękuje za komentarz! Czy możesz mi wyjaśnić, w jaki sposób Twoje rozwiązanie przyspiesza działanie! Zawsze chętny, aby dowiedzieć się więcej :)
Kyriakos,
Kiedy kończy -execsię ;, {}otrzymuje jedną ścieżkę naraz. Dostajesz osobny cpdla każdego pliku. Z +składniowych findreplaces {}z wieloma wynikami (do granicy systemowej zdefiniowanej długości linii poleceń ograniczeń: {}musi być ostatnią rzeczą przed +, stąd cp -t). Tworzenie i kończenie procesu jest względnie kosztowne. Z tego powodu warto go używać, +gdy oczekuje się wielu wyników. W takim przypadku kopiowanie dużej liczby plików i tak może zająć dużo czasu, więc różnica może minąć niezauważona; niemniej jednak jest to dobra praktyka.
Kamil Maciorowski
1

Grep można zastąpić za pomocą polecenia find's -name :

find src/ -type f -name "*.so" | xargs -i cp {} dst/{}
Th. Thielemann
źródło