Existe alguma desvantagem de usar rm $ (ls) para excluir arquivos?

13

Eu queria saber se usar rm $(ls) para excluir arquivos (ou rm -r $(ls) para excluir diretórios também) era seguro? Porque em todos os sites, as pessoas dão outras maneiras de fazer isso, embora este comando pareça muito mais fácil do que outros comandos.

    
por posixKing 03.09.2016 / 03:35

2 respostas

7

O que isso pretende fazer?

  • ls lista arquivos no diretório atual
  • $(ls) substitui a saída de ls coloca como argumento para rm
  • Essencialmente rm $(ls) destina-se a excluir todos os arquivos no diretório atual

O que há de errado com essa foto?

ls não pode manipular corretamente caracteres especiais no nome do arquivo. Usuários de Unix geralmente recomendam usar abordagens diferentes. Eu também mostrei isso em uma pergunta relacionada sobre a contagem de nomes de arquivos . Por exemplo:

$ touch file$'\n'name                                                                                                    
$ ls                                                                                                                     
file?name
$ rm $(ls)
rm: cannot remove 'file': No such file or directory
rm: cannot remove 'name': No such file or directory
$ 

Além disso, conforme mencionado na resposta de Denis, um nome de arquivo com traços iniciais pode ser interpretado como argumento para rm após a substituição, o que anula o propósito de remover o nome do arquivo.

O que funciona

Você deseja excluir arquivos no diretório atual. Então use glob rm * :

$ ls                                                                                                                     
file?name
$ rm $(ls)
rm: cannot remove 'file': No such file or directory
rm: cannot remove 'name': No such file or directory
$ rm *
$ ls
$ 

Você pode usar o comando find . Esta ferramenta é freqüentemente recomendada para mais do que apenas o diretório atual - ela pode percorrer recursivamente a árvore de diretório inteira e operar em arquivos via -exec . . .{} \;

$ touch "file name"                                
$ find . -maxdepth 1 -mindepth 1                                                                                         
./file name
$ find . -maxdepth 1 -mindepth 1 -exec rm {} \;                                                                          
$ ls
$ 

O Python não tem problemas com caracteres especiais em nomes de arquivos, então podemos empregar isso também (note que este é apenas para arquivos, você precisará usar os.rmdir() e os.path.isdir() se você quiser operar diretórios):

python -c 'import os; [ os.remove(i) for i in os.listdir(".") if os.path.isfile(i) ]'

Na verdade, o comando acima pode ser transformado em função ou alias em ~/.bashrc para brevidade. Por exemplo,

rm_stuff()
{
    # Clears all files in the current working directory
    python -c 'import os; [ os.remove(i) for i in os.listdir(".") if os.path.isfile(i) ]'

}

Versão em Perl disso seria

perl -e 'use Cwd;my $d=cwd();opendir(DIR,$d); while ( my $f = readdir(DIR)){ unlink $f;}; closedir(DIR)'
    
por Sergiy Kolodyazhnyy 03.09.2016 / 03:49
28

Não, não é seguro, e a alternativa comumente usada rm * não é muito mais segura.

Existem muitos problemas com rm $(ls) . Como outros já cobriram as respostas, a saída de ls será dividida em caracteres presentes no interno separador de campos .

Melhor cenário, simplesmente não funciona. Na pior das hipóteses, você pretendia remover apenas arquivos (mas não diretórios) - ou remover seletivamente alguns arquivos com -i -, mas há um arquivo com o nome c -rf no diretório atual. Vamos ver o que acontece.

$ mkdir a
$ touch b
$ touch 'c -rf'
$ rm -i $(ls)
$ ls
c -rf

O comando rm -i $(ls) deveria remover apenas os arquivos e perguntar antes de remover cada um deles, mas o comando que foi executado, em última análise, foi lido

rm -i a b c -rf

então fez outra coisa completamente diferente.

Observe que rm * é apenas marginalmente melhor. Com a estrutura de diretórios como antes, ela se comportará como pretendido aqui, mas se você tiver um arquivo chamado -rf , ainda estará sem sorte.

$ mkdir a
$ touch b
$ touch ./-rf
$ rm -i *
$ ls
-rf

Existem várias alternativas melhores. Os mais fáceis envolvem apenas rm e globbing.

  • O comando

    rm -- *
    

    funcionará exatamente como pretendido, em que -- sinaliza que tudo após isso não deve ser interpretado como uma opção.

    Isso faz parte das diretrizes de sintaxe do utilitário POSIX há mais de duas décadas. É difundido, mas você não deve esperar que esteja presente em todos os lugares.

  • O comando

    rm ./*
    

    faz o glob expandir de forma diferente e, portanto, não requer suporte do utilitário chamado.

    Para o meu exemplo acima, você pode ver o comando que será executado com a inclusão de echo .

    $ echo rm ./*
    rm ./a ./b ./-rf
    

    O principal ./ impede que rm processe acidentalmente qualquer um dos nomes de arquivos como opções.

por Dennis 03.09.2016 / 06:31