Polecenie Grep, aby znaleźć pliki zawierające ciąg tekstowy i przenieść je

15

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?

Spartanblogger
źródło
Oto jest. grep -i -Z -r -l 'string' . | xargs -I{} mv {} ./folder_name
Alan Dong

Odpowiedzi:

10

Jak zawsze, uważaj grep -r. -rnie 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.

Stéphane Chazelas
źródło
to daje mi błąd find: `grep 'zakończony sygnałem 13. jakiś pomysł co się dzieje?
Reena Parekh,
@ReenaParekh, to byłby SIGPIPE. Stałoby się tak tylko, jeśli wyjdzie xargsprzed 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.
Stéphane Chazelas,
15

Użyj xargsw połączeniu z mvtrzecią 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 grepma opcję -Z/ --null, aby zakończyć nazwy plików na NUL.

Alternatywą dla trzeciej składni mvjest użycie xargsz symbolem zastępczym string ( -I).

Inną opcją jest podstawianie poleceń - $( )lub backsticks ``(w bash), jak wspomniano w odpowiedzi ire_and_curses.

Peter
źródło
3
gnu grep obsługuje flagę -Z do oddzielania nazw plików od znaku bajtu zerowego, który w połączeniu z flagą -0 dla xargs może ominąć problem ze znakami specjalnymi, o których wspomniałeś
iruvar
@ChandraRavoori dzięki, zaktualizowałem odpowiedź.
peterph
7

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/
ire_and_curses
źródło
Backticks są przestarzałe; zamiast tego użyj bardziej przenośnego, czytelnego i ustawialnego $ (...).
użytkownik nieznany
2

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 -Fopcja (naprawione wyszukiwanie ciągów) grepwydaje się odpowiednia.

Jeśli katalog docelowy znajduje się w dowolnym miejscu w katalogu wyszukiwania, możesz mieć nieprzyjemne warunki wyścigu.

Specyfikacja POSIX dla grep

Specyfikacja POSIX dla find

Dzika karta
źródło
To może być najlepsze rozwiązanie na Macos / BSD
Ali
0

Używanie GNU równoległego :

grep -i -Z -r -l 'string' . | parallel 'mv {} destination/{}'

ht / @ lin-dong za oryginalną odpowiedź na xargs.

zach
źródło
Byłoby miło, gdybyś podał odpowiedź @ lindong w komentarzach sprzed ponad roku.
roaima,
0

-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 /

SURESH BABU
źródło