Jestem w stanie zlokalizować pliki w folderze zawierającym określony ciąg tekstowy za pomocą tego polecenia:
grep -lir 'string' ~/directory/*
Jak przenieść pliki z powyższego wyniku do innej lokalizacji?
Jestem w stanie zlokalizować pliki w folderze zawierającym określony ciąg tekstowy za pomocą tego polecenia:
grep -lir 'string' ~/directory/*
Jak przenieść pliki z powyższego wyniku do innej lokalizacji?
Odpowiedzi:
Jak zawsze, uważaj grep -r
. -r
nie jest standardową opcją, a w niektórych implementacjach, takich jak wszystkie oprócz najnowszych wersji GNU grep
, podąża za dowiązaniami symbolicznymi podczas schodzenia z drzewa katalogów, co na ogół nie jest tym, czego chcesz i może mieć poważne konsekwencje, jeśli na przykład istnieje dowiązanie symboliczne do „/ „gdzieś w drzewie katalogów.
W filozofii uniksowej używasz polecenia do przeszukiwania katalogów w poszukiwaniu plików, a drugiego do przeglądania jego zawartości.
Korzystając z narzędzi GNU, zrobiłbym:
xargs -r0 --arg-file <(find . -type f -exec grep -lZi string {} +
) mv -i --target-directory /dest/dir
Ale nawet wtedy uważaj na warunki wyścigu i możliwe problemy z bezpieczeństwem, jeśli uruchomisz go jako jeden użytkownik w katalogu, który może zapisać inny użytkownik.
xargs
przed przeczytaniem do końca pliku arg, co nie powinno się zdarzyć, chyba że xargs zostanie zabity sam lub zawiedzie z jakiegokolwiek powodu, w takim przypadku spodziewam się, że również zobaczysz błąd.
Użyj xargs
w połączeniu z mv
trzecią składnią:mv [OPTION]... -t DIRECTORY SOURCE...
grep -lir 'string' ~/directory/* | xargs mv -t DEST
Uważaj na pliki zawierające znaki specjalne (spacje, cudzysłowy). W takim przypadku filtrowanie listy za pomocą sed
(dodawanie cudzysłowów wokół nazw plików za pomocą s/^/'/;s/$/'/
) może pomóc, ale musisz mieć pewność, że te cytaty nie pojawią się w nazwach plików. GNU grep
ma opcję -Z
/ --null
, aby zakończyć nazwy plików na NUL.
Alternatywą dla trzeciej składni mv
jest użycie xargs
z symbolem zastępczym string ( -I
).
Inną opcją jest podstawianie poleceń - $( )
lub backsticks ``
(w bash), jak wspomniano w odpowiedzi ire_and_curses.
Jeśli nazwy plików nie zawierają żadnych znaków specjalnych (białe znaki lub \[*?
), użyj podstawienia polecenia :
mv `grep -lir 'string' ~/directory/*` destination/
Używając tylko określonych funkcji POSIX i nie przyjmując żadnych założeń dotyczących nazw plików:
find ~/directory -type f -exec grep -qiF 'string' {} \; -exec mv {} /path/to/dest \;
Uwagi:
Powiedziałeś „ciąg” nie „wzorzec”, więc -F
opcja (naprawione wyszukiwanie ciągów) grep
wydaje się odpowiednia.
Jeśli katalog docelowy znajduje się w dowolnym miejscu w katalogu wyszukiwania, możesz mieć nieprzyjemne warunki wyścigu.
Używanie GNU równoległego :
grep -i -Z -r -l 'string' . | parallel 'mv {} destination/{}'
ht / @ lin-dong za oryginalną odpowiedź na xargs.
-Załóż, że masz katalog docelowy jako „zewnętrzny” i musisz przenieść wszystkie pliki XLS, możesz wypróbować poniższe polecenie
sudo mv find /var/log/ -type f -name "*.xls"
/ external /
grep -i -Z -r -l 'string' . | xargs -I{} mv {} ./folder_name