Algo que sinto que devo ter certeza: se remover ls <something>
, rm <something>
removerei exatamente os mesmos arquivos ls
exibidos? Existe alguma circunstância em que você rm
possa remover arquivos que ls
não foram exibidos? (Isso é no bash 18.04)
Edit: obrigado a todos que responderam. Penso que a resposta completa é uma combinação de todas as respostas, pelo que aceitei a resposta mais votada como "a resposta".
Coisas inesperadas que aprendi ao longo do caminho:
ls
não é tão simples quanto você imagina ao lidar com seus argumentos- Em uma instalação simples e sem complicações do Ubuntu, aliases .bashrc
ls
- Não nomeie seus arquivos começando com um hífen, pois podem parecer argumentos de comando, e nomear um -r é pedir!
rm
não tenha uma--dry-run
bandeira ...find -delete
seria melhor do querm
? Você diz "É por isso" , mas não está totalmente claro para mim a que isso se refere. Observe também que suafind
chamada excluirá todos os arquivos recursivamente no diretório atual, onderm
apenas excluirá os arquivos no diretório imediato. Também-name *
é um no-op. Tudo em tudo, estou muito intrigado com o seu conselho ...find
é que você pode executá-lo, ver todos os arquivos e, em seguida, executar o mesmo comando com-delete
. Desde que você já viu os resultadosfind
, não deve haver nenhuma ambigüidade ao que será removido (que eu realmente gostaria de ouvir mais detalhes sobre isso na forma de uma resposta)-delete
" - Mas como isso é melhor do que executarls <filespec>
, seguido porrm <filespec>
(que o OP já sabe como fazer)?find ... -print
primeiro para confirmar quais arquivos serão excluídos efind ... -delete
, em seguida , ainda excluirá os arquivos criados entre os dois comandos. Se você usa os dois-print
e-delete
não obtém confirmação, apenas um relatório posterior do que foi excluído (e você também pode usarrm -v
).Respostas:
Bem, ambos
ls
erm
operam com os argumentos que lhes são passados.Estes argumentos podem ser um arquivo simples, tão
ls file.ext
erm file.ext
operar o mesmo arquivo e o resultado é claro (lista o arquivo / excluir o arquivo).Se, ao invés argumento é um diretório,
ls directory
lista o conteúdo do diretório enquantorm directory
não funcionará como está (ou seja,rm
sem bandeiras não pode remover diretórios, enquanto que se você fizerrm -r directory
, ele recursivamente apaga todos os arquivos sobdirectory
eo próprio diretório ).Mas lembre-se de que os argumentos da linha de comando podem estar sujeitos à expansão do shell , portanto, nem sempre é garantido que os mesmos argumentos sejam transmitidos aos dois comandos se eles contiverem caracteres curinga, variáveis, saída de outros comandos etc.
Como exemplo extremo, pense
ls $(rand).txt
erm $(rand).txt
, os argumentos são "os mesmos", mas os resultados são bem diferentes!fonte
ls
vsrm *
onde há arquivos "ocultos" (ponto), embora mesmo isso não seja uma comparação justa, pois eu não escrevils *
. Masrm
não tem sentido por si só, então a coisa toda é realmente maçãs e laranjas. Se eu entendi corretamente, esse é o ponto crucial da sua resposta, tão bom trabalho :)ls
vsrm -r
: o comandols <directory>
não vai mostrar arquivos escondidos dentro do diretório, masrm -r <directory>
vai eliminar até mesmo os arquivos ocultos.ls
não os listará (a menos que seja aliasadols -a
) erm *
não os excluirá (a menos que você tenhadotglob
definido).Se você estiver pensando em algo como
ls foo*.txt
vs.rm foo*.txt
, sim, eles mostrarão e removerão os mesmos arquivos. O shell expande a glob e a passa para o comando em questão, e os comandos funcionam nos arquivos listados. Um listando-os, um removendo-os.A diferença óbvia é que, se algum desses arquivos fosse um diretório,
ls
ele listaria seu conteúdo, masrm
falharia em removê-lo. Isso geralmente não é um problema, poisrm
removeria menos do que o mostrado porls
.O grande problema aqui vem da execução
ls *
ourm *
em um diretório que contém nomes de arquivos começando com um traço . Eles iriam se expandir para as linhas dos dois programas de comando como se você escreveu-los você mesmo, els
levaria-r
para significar "ordem de classificação inversa", enquanto querm
levaria-r
a significar uma remoção recursiva. A diferença importa se você tiver subdiretórios com pelo menos dois níveis de profundidade. (ls *
mostrará o conteúdo dos diretórios de primeiro nível, mas tambémrm -r *
passará tudo além do primeiro subnível.)Para evitar isso, escreva globs permissivos com uma
./
indicação para indicar o diretório atual e / ou coloque a--
para sinalizar o final do processamento da opção antes da glob (ierm ./*
ourm -- *
).Com um glob como
*.txt
, na verdade, isso não é um problema, pois o ponto é um caractere de opção inválido e causará um erro (até que alguém expanda os utilitários para inventar um significado para ele), mas ainda é mais seguro colocar o./
local de qualquer maneira.É claro que você também pode obter resultados diferentes para os dois comandos se alterar as opções de brilho do shell ou criar / mover / remover arquivos entre os comandos, mas duvido que você tenha se referido a algum desses casos. (Lidar com arquivos novos / movidos seria extremamente complicado de fazer com segurança.)
fonte
Deixando de lado o comportamento do shell, vamos nos concentrar apenas no que
rm
els
podemos lidar com eles mesmos. Pelo menos um caso emls
que o querm
não pode ser removido envolve permissões de diretório e o outro - diretórios especiais.
e..
.Permissões de pasta
rm
é uma operação em um diretório, porque, ao remover um arquivo, você altera o conteúdo do diretório (ou, em outras palavras, a lista de entradas do diretório, pois o diretório não é mais do que uma lista de nomes de arquivos e inodes ). Isso significa que você precisa de permissões de gravação em um diretório. Mesmo se você for o proprietário do arquivo , sem permissões de diretório, você não poderá remover os arquivos. O inverso também é verdadeiro :rm
pode remover arquivos que pertencem a outras pessoas, se você for o proprietário do diretório.Portanto, você pode muito bem ter permissões de leitura e execução em um diretório, o que permitirá que você percorra o diretório e visualize o conteúdo muito bem, por exemplo
ls /bin/echo
, mas você não pode, arm /bin/echo
menos que seja o proprietário/bin
ou aumente seus privilégiossudo
.E você verá casos como esse em todos os lugares. Aqui está um desses casos: https://superuser.com/a/331124/418028
Diretórios especiais '.' e '..'
Outro caso especial é
.
e..
diretórios. Se você fazls .
ouls ..
, felizmente irá mostrar-lhe o conteúdo, masrm
'ing-los não é permitido:fonte
Se você digitar
ls *
erm *
, em seguida , é possível remover mais arquivos do que ols
mostrado - eles podem ter sido criados no pequeno intervalo de tempo entre o finalls
e o início derm
.fonte
/tmp
, onde muitos aplicativos podem criar arquivos temporários, portanto, essa é sempre uma possibilidade nos dois comandos*
. No entanto, alguns aplicativos também tornam os arquivos anônimosunlink()
, mantendo-os abertos, para que ele apareça,ls *
masrm *
não o consiga.*
a diferença entre o quels
seria exibido e o querm
funciona, porque a listagem do conteúdo do diretório mudou no meio.ls *
poderia mostrar o nome do arquivo que já se foi.ls *
erm *
não somos responsáveis por expandir a glob - isso é feito pelo shell antes de passá-lo ao comando.Isso significa que você pode usar qualquer comando com a lista de arquivos expandida - então eu usaria algo que faça o mínimo possível.
Portanto, uma maneira melhor de fazer isso (ou pelo menos de outra maneira) é pular o intermediário.
echo *
mostrará exatamente o que seria passado ao seurm
comando.fonte
printf "%s\n" *
para obter uma visão inequívoca dos nomes de arquivos com espaços. (Ou%q
, em vez de lidar com novas linhas e caracteres de controle também, à custa de mais feio de saída.)E se:
Basicamente, os curingas que se expandem para itens iniciados por
-
(ou itens inseridos manualmente, iniciados com-
mas que se parecem um pouco com trapaça) podem ser interpretados de forma diferente porls
erm
.fonte
Não são casos extremos onde o que
ls
mostra não é o querm
remove. Um argumento bastante extremo, mas felizmente benigno, é se o argumento que você passa é um link simbólico para um diretório:ls
mostrará todos os arquivos no diretório com link simbólico, enquantorm
removerá o link simbólico, deixando o diretório original e seu conteúdo intocado:fonte
ln -s $HOME some_link; ls some_link
saídassome_link@
para mim, mas eu tenhols
alias parals -F
. Aparentemente,-F
altera o comportamento para mostrar o link em vez de desreferencia-lo. Não esperava isso.ls -l
por exemplo, segmenta o link, não o destino ... deve haver maneiras de inspecionar o próprio link.ls
erm
.ls some_link/
,ls -H some_link
ouls -L some_link
, ele irá listar o-linked para o diretório, mesmo se você adicionar-F
ou-l
. Inversamente (mais ou menos),-d
diz olhar para um diretório em vez de seu conteúdo; compararls -l /tmp
els -ld /tmp
.ls
. Você está mostrando basicamente por isso enumerando comportamentos com diferentes bandeiras não vale o incômodo para esta pergunta ...Se você fizer isso apenas em
ls
vez dels -a
, sim,rm
poderá remover os arquivos ocultos que você não viuls
sem-a
.Exemplo:
De acordo com :
ls dir_test
: exibirá apenas test2ls -A dir_test
: exibirá test2 + .testrm -r dir_test
: removerá tudo (.test + test2)Espero que isso ajude você.
fonte
rm *
não removerá os arquivos de ponto. Se isso acontecer,ls *
também os mostrará.ls *
não exiba arquivos ocultos.ls -a
irá listar.
,..
,.test
etest2
. Você pode alterar seu exemplo para usarls -A
, que lista tudo, exceto.
e..
(ou seja, somente.test
etest2
).Já existem muitas respostas boas, mas quero acrescentar uma visão mais profunda.
Faça a si mesmo a pergunta: Quantos parâmetros são passados para
ls
, se você escrever...? Observe que o
ls
comando não obtém o*
parâmetro as se houver algum arquivo que*
possa ser expandido. Em vez disso, o shell primeiro executa um globbing antes de chamar o comando, de modo que ols
comando realmente obtém tantos parâmetros quanto os arquivos correspondentes ao globbing. Para suprimir globbing, cite o parâmetroIsto é verdade para qualquer comando:
echo *
vsecho '*'
.Existe um script, chame-o
countparams.sh
para testar o efeito. Ele informa quantos parâmetros foram passados e os lista.Torne executável e execute
./countparams.sh *
. Aprenda com sua saída!fonte
A glob se expandirá da mesma maneira nas duas vezes, se o conteúdo do diretório for o mesmo nesses dois momentos diferentes.
Se você realmente deseja verificar o que será removido, use
rm -i *.txt
. Ele solicitará separadamente cada arquivo antes (tentando) removê-lo.Isso garante segurança contra as condições de corrida:
ls *.txt
/ um novo arquivo é criado /rm *.txt
porque você é solicitado a cada arquivo pelo mesmo programa que está fazendo a remoção.
Este é demasiado pesado para o uso normal, e se você apelido
rm
pararm -i
, você vai encontrar-se usando\rm
ourm -f
com bastante frequência. Mas vale a pena mencionar pelo menos que existe uma solução para a condição de corrida. (É até portátil para sistemas não-GNU: POSIXrm(1)
especifica a-i
opção .)Outra opção seria uma matriz bash:,
to_remove=(*.txt)
então peça ao usuário para confirmar (talvez depois de fazerls -ld -- "${to_remove[@]}"
), entãorm -- "${to_remove[@]}"
. Portanto, a expansão glob é feita apenas uma vez e a lista é passada literalmente pararm
.Outra opção praticamente utilizável é o GNU
rm -I
( página de manual ), que solicita a remoção de mais de 4 itens. (Mas não mostra a lista, apenas o total.) Usoalias rm='rm -I'
na minha área de trabalho.É uma boa salvaguarda contra o retorno dos dedos gordos com um padrão meio digitado que combina demais. Mas usar
ls
primeiro é geralmente bom em um diretório que você possui, ou em um sistema de usuário único, e quando não há processos em segundo plano que poderiam criar novos arquivos de forma assíncrona. Para se proteger contra dedilhado gordo, não digiterm -rf /foo/bar/baz
da esquerda para a direita.rm -rf /
é especial, masrm -rf /usr
não é! Deixe de fora a-rf
peça ou comece com elals
e adicione-a somenterm -rf
depois de digitar o caminho.fonte