Eu queria saber se o uso rm $(ls)
para excluir arquivos (ou rm -r $(ls)
excluir diretórios também) era seguro? Porque em todos os sites, as pessoas dão outras maneiras de fazer isso, mesmo que esse comando pareça muito mais fácil do que outros comandos.
13
touch 'foo -r .. bar'
;rm $(ls)
; onde foi meu diretório pai? Além disso, que tipo de alternativas você vê que são ainda mais complicadas do que isso?rm *
é muito mais fácil digitar e pensar, e mais seguro (mas não perfeitamente seguro; veja a resposta de Dennis).ls
pode variar entre implementações e, portanto, não é padrão. Dependendo do que você precisa, considere alternativas comofind
estat
. Você deve usarls
apenas para consumo humano, nunca para uso por outros comandos ou scripts.Respostas:
O que isso pretende fazer?
ls
lista arquivos no diretório atual$(ls)
substitui a saída dels
lugares que, como argumento pararm
rm $(ls)
objetivo é excluir todos os arquivos no diretório atualO que está errado com esta imagem ?
ls
não pode lidar adequadamente com caracteres especiais no nome do arquivo. Usuários do Unix geralmente recomendam usar abordagens diferentes . Também mostrei isso em uma pergunta relacionada sobre a contagem de nomes de arquivos . Por exemplo:Além disso, como corretamente mencionado na resposta de Denis, um nome de arquivo com os principais traços, poderia ser interpretado como argumento para
rm
após a substituição, o que frustra a finalidade de remover nome de arquivo.O que funciona
Você deseja excluir arquivos no diretório atual. Então use glob
rm *
:Você pode usar o
find
comando Essa ferramenta é frequentemente recomendada para mais do que apenas o diretório atual - ela pode percorrer recursivamente toda a árvore de diretórios e operar em arquivos via-exec . . .{} \;
O Python não possui problemas com caracteres especiais nos nomes de arquivos, portanto, podemos empregá-lo também (observe que este é apenas para arquivos, você precisará usar
os.rmdir()
eos.path.isdir()
se desejar operar em diretórios):De fato, o comando acima pode ser transformado em função ou alias
~/.bashrc
por uma questão de brevidade. Por exemplo,Versão Perl disso seria
fonte
"$(ls)"
exemplo funciona apenas se houver apenas um arquivo no diretório Você também pode usar a conclusão de tabulação para expandir o nome do arquivo, pois é a única conclusão.ls
então :) Vou editar it out$(ls)
para desativar a divisão de palavras ou permite que a divisão de palavras aconteça (com resultados desastrosos). A única maneira limpa de passar uma lista de várias seqüências de caracteres sem tratar os dados como código é com variáveis de matriz ou\0
como separador, mas o próprio shell não pode fazer isso. AindaIFS=$'\n'
é o menos perigoso, mas não pode igualarfind -print0 | xargs -0
. Orgrep -l --null
. Ou você evita todo o problema com coisas do tipofind -exec rm {} +
. (Observe+
para passar vários argumentos a cada chamada de rm; MUITO MAIS eficiente).IFS=$'\n'
também falhará neste caso, já que eu tenho uma nova linha no nome do arquivo, portanto, a divisão de palavras o tratará como dois nomes de arquivos em vez de um. A estranha razão, no entanto, é o fato de que, por padrão,IFS
que é espaço, guia, nova linha, originalrm "$(ls)"
, também deve falhar, deve tratar como eu disse o nome do arquivo como dois separados, mas não o fez. Normalmente eu usofind
com-exec
, oufind . . .-print0 | while IFS= read -d'' FILENAME ; do . . . done
estrutura, para lidar com nomes de arquivos. Ou alguém poderia usarpython
, eu adicionei exemplo disso."$(ls)"
sempre se expande para um argumento, porque as aspas protegem a expansão da$(ls)
divisão de palavras. Assim como eles protegem"$foo"
.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á abordaram em suas respostas, a saída dels
será dividida nos caracteres presentes no separador de campo interno .Na melhor das hipóteses, simplesmente não funciona. No pior cenário, você pretendia remover apenas arquivos (mas não diretórios) - ou remover seletivamente alguns arquivos
-i
- mas há um arquivo com o nomec -rf
no diretório atual. Vamos ver o que acontece.O comando
rm -i $(ls)
deveria remover apenas arquivos e perguntar antes de remover cada um, mas o comando que acabou sendo executado leuentão fez algo completamente diferente.
Observe que
rm *
é apenas um pouco 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.Existem várias alternativas melhores. Os mais fáceis envolvem apenas rm e globbing.
O comando
funcionará exatamente como pretendido, onde
--
sinaliza que tudo depois 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. É generalizada, mas você não deve esperar que ela esteja presente em todos os lugares.
O comando
faz com que a glob se expanda de maneira diferente e, portanto, não requer suporte do utilitário chamado.
Para o meu exemplo acima, você pode ver o comando que será executado em última análise, com o eco precedente .
O líder
./
impede que a rm trate acidentalmente qualquer um dos nomes de arquivo como opções.fonte
rm
. +1touch 'foo -rf .. bar
. Eu não acho que um invasor possa ficar mais alto que o diretório pai, a menos que possamos produzir um separador de caminho nals
saída.rm: refusing to remove '.' or '..' directory: skipping '..'
ou algo semelhante ao tentar remover o diretório pai.