No Linux, como posso encontrar todos os arquivos que contêm uma string e excluí-los?

17

Eu quero excluir todos os arquivos que contêm a string foo. Como posso fazer isso usando o bash no Linux?

Kitsos
fonte
essa string é o nome do arquivo?
rɑːdʒɑ
3
Por favor, esclareça: você deseja excluir arquivos cujo nome contenha foo(por exemplo myfoo.jpg) ou arquivos que contenham a sequência de bytes foo(que podem incluir arquivos binários que por acaso contenham essa sequência de bytes)?
Hammar

Respostas:

33

Aqui está uma maneira segura:

grep -lrIZ foo . | xargs -0 rm -f --
  • -l imprime nomes de arquivos que correspondem ao padrão de pesquisa.
  • -rrealiza uma pesquisa recursiva para o padrão foono diretório especificado .. Se isso não funcionar, tente -R.
  • -I(capital i) faz com que arquivos binários como PDFs sejam ignorados.
  • -Z garante que os nomes dos arquivos sejam zerados (ou seja, nul-), para que um nome contendo espaço em branco não seja interpretado da maneira errada (ou seja, como vários nomes em vez de um).
  • xargs -0alimenta os nomes dos arquivos de greppara rm -f, separando as palavras por zero (nul) bytes (lembre-se da -Zopção de grep).
  • --é frequentemente esquecido, mas é muito importante marcar o final das opções e permitir a remoção de arquivos cujos nomes começam com -.

Se você deseja ver quais arquivos estão prestes a serem excluídos, remova a | xargs -0 rm -f --peça e deixe a Zopção para grep.

Outro usuário sugeriu algo como o seguinte, que você não deve executar porque não é seguro:

files=`grep foo * | cut -d: -f1`
rm -f $files         # unsafe, do not run it!

Se eu tiver arquivos ImportantStuffque não desejo excluir e obsolete ImportantStuffconter foo, perco ImportantStuff(e não obsolete ImportantStuff !) Quando executo esse comando, porque $filesé desmembrado em espaços quando é interpretado. É perigoso colocar uma lista de nomes de arquivos em uma variável de shell escalar dessa maneira.

Lekensteyn
fonte
17
$ find -type f -exec grep -q "foo" {} \; -exec echo rm -- {} \;

Isso recursivamente procura por arquivos que contenham foo. O segundo -execsó é executado se o primeiro execsair com êxito, ou seja, se grepcorresponder. Dryrun e remova o echose a saída parece correta.

Ou alternativamente

$ find -type f -exec grep -q "foo" {} \; -print

e

$ find -type f -exec grep -q "foo" {} \; -delete

como sugerido por Lekensteyn.

Adrian Frühwirth
fonte
4
... que pode ser reduzido para: find -type f -exec grep -q 'foo' {} \; -delete(as aspas {}são redundantes, findtambém é possível excluir arquivos.). Observe que grepaceita uma expressão regular. Se você deseja procurar foo.bar, escape ou passe a -Fopção de tratar o padrão como literal.
Lekensteyn
alguma razão para usar -exec echo rm "{}" \;e não -delete?
vartec
11
@artec Não, eu usaria -delete. É mais fácil demonstrar com o segundo -exece eco no lugar.
Adrian Frühwirth
11
É mais fácil digitar -print(ou -lspara mais verbosidade) que -exec echo rm "{}" \'. Não há necessidade de utilitários externos.
Lekensteyn
11
se você usar rm {}, use rm - {}, para que nenhum caractere especial no nome do arquivo seja interpolado. Por exemplo, toque em '-rf /' em qualquer diretório em que você tenha permissões de gravação ...
atk
1

Eu faria o que Adrian diz,

Mas eu adicionaria limites de palavras ao redor para não excluir acidentalmente arquivos que contenham "comida" (a menos que esteja excluindo tudo o que contém comida é o que você deseja).

 $ find -type f -exec grep -q "\<foo\>" {} \; -delete

agudamente, redirecionaria a saída antes de excluir para poder revisar antes de excluir:

 $ find -type f -exec grep -q "\<foo\>" > /tmp/list_of_files_to_delete
Petter H
fonte
Assim que puder postar comentários, você deve postar coisas assim como comentários.
FSMaxB
sim, tentei primeiro, mas depois percebi que ainda não tenho permissão para postar comentários.
precisa