Impedir que o usuário digite espaço acidental entre rm e curinga

29

Intenção:

rm -rf string*

Problema:

rm -rf string *

O primeiro caso é um uso legítimo e comum da rm, um pequeno erro de digitação pode causar muitos problemas no segundo caso. Existe uma maneira simples de proteger com inteligência contra um curinga acidental à direita ou à direita?

bobdole
fonte
8
Com uma concha recente e bem configurado ( zshou bash) Eu preferiria tomar o hábito de pressionar a tecla Tab (para acionar auto-realização) antes de pressionar a tecla Enter
Basile Starynkevitch
2
touch -- -icriará um arquivo -ique será passado rmcomo parâmetro -iquando você incluir um curinga em seus argumentos.
Reintegrar Monica - M. Schröder
@ MartinSchröder: Se você estiver no diretório em que o arquivo existe.
Pausado até novo aviso.
@ MartinSchröder Isso só funcionará se você digitar rm *. Se você digitar rm name *, ele será expandido para rm name -i other names. -inão será processado como uma opção, porque não é antes dos nomes dos arquivos.
Barmar 16/01
1
Normalmente, um usuário faz isso apenas uma vez.
precisa saber é o seguinte

Respostas:

37

Uma DEBUGarmadilha pode ser gravada para cancelar comandos que parecem suspeitos. O seguinte, ou código semelhante, pode ser adicionado ao seu ~/.bashrc:

shopt -s extdebug
checkcommand() {
  if [[ $BASH_COMMAND = 'rm -r'*' *' ]]; then
    echo "Suppressing rm -r command ending in a wildcard" >&2
    return 1
  fi
  # check for other commands here, if you like
  return 0
}
trap checkcommand DEBUG

Ajuste a lógica a gosto.

(Na verdade, não espero que essa abordagem seja útil - muitas maneiras de atrapalhar um comando destrutivamente para encontrá-los testando um por um - mas fornece uma resposta literal à pergunta).

Charles Duffy
fonte
47

Não há como um sistema totalmente à prova de balas. E adicionando "Você tem certeza?" solicitar informações é ao mesmo tempo contraproducente e leva a "Claro que tenho certeza". reações no joelho.

Um truque que aprendi em um livro nos últimos anos é fazer primeiro ls -R blah*, fazer rm -fr blah* se, e somente se, a listagem que apareceu apareceu no que eu queria.

É fácil o suficiente executar o lscomando primeiro e, em seguida , excluir ls -Re substituir por rm -fr.

A pergunta final é: "Se a informação foi valiosa para você, onde está seu backup?"

assassino
fonte
4
Ao invés de seta para cima você pode usar ^ls -R^rm -rf^e talvez definir como um alias
exussum
FWIW, é isso ls -Rque eu basicamente faço o tempo todo, mas é tão instintivo neste ponto que deslizou minha mente consciente quando me formei pela resposta. Então, +1 para isso.
precisa saber é o seguinte
Isso também tem a vantagem de não causar danos se você pressionar a tecla Enter ou pressionar o mouse e colar algo com novas linhas. Às vezes, insiro as coisas em uma ordem menos eficiente apenas para maior segurança, por exemplo cat > .log, depois volto e colo ou puxo o nome do arquivo antes do .log. Então, em nenhum momento eu tenho > valuablefileo cmdline.
Peter Cordes
Eu uso rm alias para rm -i, então geralmente componho meu comando rm e depois coloco um \ no início da linha. ( \rmevita expansão de alias para rm, já que parte da palavra foi citada). Se eu precisasse de um -rou -f, sim, às vezes começo com, em lsvez de rm, ou simplesmente deixo de fora a -rfparte. ? (editar, como você começa uma barra invertida code-formatação bquote bslash bslash bquote falhar.
Peter Cordes
8

Você pode treinar para usar, digamos, rmrfno lugar de rm -rf?

Nesse caso, essa função bash fornecerá uma chance de ver o que realmente aconteceria antes de confirmar o comando:

rmrf() { echo rm -rf "$@"; read -p "Proceed (y/N)? "; [ "${REPLY,,}" = y ] && rm -rf "$@"; }

Para tornar essa função permanente, adicione esta linha ao ~/.bashrcarquivo em cada computador que você usa.

Comparação com o rmalias comum

É comum definir um alias:

alias rm='rm -i'

Isso tem duas limitações:

  1. Se você depender desse alias, sofrerá um choque quando estiver em uma máquina ou em um ambiente que não o possui. Por outro lado, tentar executar rmrfuma máquina sem essa função retornará um efeito inofensivo command not found.

  2. Esse alias não ajuda no seu caso, porque a -fopção que você fornece na linha de comando substitui a -iopção no alias.

John1024
fonte
4
Não é uma má ideia. Mas isso depende dessa função estar instalada e disponível em qualquer sistema que esse usuário esteja usando. Então, digamos que eles entrem em um servidor remoto para algum trabalho e executem o rm -rfcomando errado , o que acontece? A criação de pseudo-funções como essa acaba por complicar uma solução simples: tenha mais cuidado e entenda o que são permissões.
precisa saber é o seguinte
4
@JakeGould E não use rm -f, a menos que você realmente precise .
um CVn 14/01
1
Por que se preocupar rmrf, em vez de apenas criar uma função shell rmque verifica os argumentos -rou -rf, e executa uma lógica especial nesse caso, caso contrário, chamava diretamente command rm "$@"para chamar o rmcomando real ?
Charles Duffy
3
Você usa um nome diferente para não dar um tiro no pé quando a substituição não está lá. E eu concordo com @ MichaelKjörling, você não precisa -fse não tiver -i. Sair -fdá um aviso extra antes de remover um arquivo somente leitura, por exemplo.
Peter Cordes
6

Se estou em uma situação onde apagar os arquivos errados é realmente um grande negócio, uma das coisas que eu tenho feito é fazer uma pasta de lixeira, como mkdir trashcan, e então eu tenho um script rmTrashcanque tem um rm -rf trashcan/*ou rm -rf *ou similar, escrito com muito cuidado e verificado várias vezes.

Dessa forma, se eu cometer um erro, o erro está em um mvcomando, não em um rmcomando. Uma vez que eu faço lse confio exatamente no que estou excluindo, um trabalho rmTrashcanrealmente sujo é feito com segurança.

Também foi tremendamente conveniente para uma situação em que tive que excluir backups. Eu pude mvum mês inteiro de backups na lixeira, mvos poucos que eu queria manter (1º de mês, 15 de mês) de volta nos backups, depois rmTranshcano resto. É difícil fazer um comando semelhante rmpor si só, e dessa maneira, deixo lsos backups confiantes nos arquivos que estou deixando para trás (em vez de apenas enumerar os arquivos que pretendo excluir)

Cort Ammon - Restabelecer Monica
fonte
4

Em vez de me preocupar com dois comandos ( lse rm), acho que uma maneira mais simples e fácil é usar find:

find . -maxdepth 1 -name "string*" -delete

Se você digitar acidentalmente, "string *"ele excluirá os arquivos nomeados string charse string letters(que é o que você queria mesmo), mas não capturará todos os arquivos como *em um shell.

Além disso, você pode deixar -deletede ver quais arquivos serão excluídos e pressionar a seta e digitar com -deletemais facilidade do que digitar ^ls -R^rm -rfou outras bobagens.

babá
fonte
A findfará uma pesquisa aninhada por arquivos que correspondam ao invés dos parâmetros explícitos declarados na linha de comando. Eu acho que isso erra o alvo. Eu posso estar errado embora.
Killermist
3

Existe uma maneira simples de proteger com inteligência contra um curinga acidental à direita ou à direita?

Na verdade não. É proposto em outra resposta que você pode criar um comando personalizado para adicionar um prompt antes de executar uma tarefa. Mas o problema com este comando personalizado é que ele deve ser instalado conscientemente nos sistemas em que você está trabalhando. E mesmo que esteja instalado, o problema é o seu reflexo ao acertar ypara concluir a tarefa e pode entrar em jogo.

Isso significa que tudo isso é um problema da interface do usuário, mesmo que esteja no nível de texto / linha de comando. Quantas redes de segurança você espera que exista para protegê-lo de fazer algo que não deveria? É como uma tesoura: se você é negligente, escorregou e cortou a mão enquanto pretendia cortar pano ou papel, quem é o culpado? Ou até mesmo semáforos e sinais de parada: não há realmente nada que impeça um motorista de acender um semáforo ou ignore os sinais de trânsito além de uma percepção aguda do que pode acontecer se eles se envolverem em um comportamento tão arriscado.

Dito isto, a melhor solução realista está nas permissões do sistema para usuários e grupos. Essa é a melhor / única rede de segurança real para proteger um usuário de si mesmo.

Se você estiver trabalhando em um sistema em que é o único a acessá-lo, poderá ficar tentado a chmod 777tudo, mas não é assim que um sistema racional é configurado. Em vez disso, as permissões devem ser algo como 755para todos os diretórios e 644todos os arquivos não executáveis. Os arquivos executáveis ​​devem ter 755no mínimo, mas talvez até mesmo 744se você quiser que outras pessoas leiam, mas não os executem.

JakeGould
fonte
2

Tente compor seu rmcomando inicial sem o -fsinalizador, mas, em -ivez disso, rmserá solicitado que você solicite cada arquivo que pretende excluir. Para pequenas exclusões recursivas, você pode manter pressionada a ytecla quando tiver certeza de que o comando foi digitado corretamente. Para exclusões grandes, é possível interromper a operação e usar o histórico da linha de comando para alterar cuidadosamente -ipara a -f.

Nevin Williams
fonte
Você realmente precisa pressionar y[RETURN]todos os arquivos, não há nada que possa conter com o GNU rm. A edição -ido caminho é o caminho a seguir, depois de digitar o comando corretamente. Em seguida, você recebe um prompt apenas em um arquivo somente leitura e talvez outras coisas.
Peter Cordes
1
Basta usar rm -Ipara que ele só pede uma vez, e apenas para eliminações potencialmente perigosos (ou seja, de muitos arquivos.)
Nick Matteo
1
Em fóruns menos construtivos, minha resposta teria sido algo como "Se sua digitação / revisão for tão ruim, você não deve usar 'rm -rf' com caracteres curinga". Eu não sabia da opção -I ... deve ter sido colocada há <20 anos atrás; sobre a última vez que fiz 'man rm'. :)
Nevin Williams 15/01
2

rm tem -ie -Isinalizadores para confirmar antes de cada remoção. No passado, algumas distribuições as ativavam por padrão. Esta é uma péssima ideia. Dê ao usuário muitas caixas de diálogo de confirmação para operações normais e elas começarão a confirmá-las habitualmente. Isso apenas muda o requisito de "ter cuidado" (sempre uma bandeira vermelha) para um novo e mais irritante diálogo. "Sim. Sim. Sim. Sim! SIM! Meu Deus, computador estúpido, basta excluir os arquivos YESYESYESYESYES - CRAP EU QUERO NÃO! NOOOOOOO!" Esse é o problema do diálogo "Sim, mas não quis dizer". Esta resposta fornece uma explicação visual do motivo pelo qual as caixas de diálogo de confirmação aparecem na hora errada.

O tipo de erro que você descreve é ​​um deslize , "a execução de uma ação que não era o que se pretendia". O usuário normalmente reconhece imediatamente o erro e sabe exatamente como corrigi-lo. Infelizmente, o Unix não oferece ao usuário a oportunidade, rm exclui o arquivo imediatamente. Todos os outros sistemas operacionais resolvem esse problema, permitindo que as exclusões sejam desfeitas, pelo menos por um tempo, pelo uso da Lixeira.

Existem vários sistemas de lixo para o Unix, e esta resposta está cheia de sugestões .

A questão é alias rm ou não alias rm. Prós para aliasing rm ...

  1. Você não pode esquecer de usar a alternativa rm.

Contras de aliasing rm ...

  1. Você pode confiar nele em sistemas que não o possuem.
  2. Pode causar problemas quando o disco está quase cheio.
  3. Precisa de infraestrutura para esvaziar o lixo periodicamente.
  4. É necessário não interferir no comportamento esperado da empresa nos programas.
  5. Pode não emular completamente a rm.

Se você seguir o primeiro argumento longe demais, acabará usando vi (não vim, vi), csh (não tcsh, csh) e outros utilitários antiquados porque eles estão disponíveis universalmente. Ainda assim, existe o risco de supercustomizar seu ambiente. Prefiro levar meus utilitários comigo e tornar isso o mais fácil possível. YMMV.

Dois e três são problemas técnicos. Eles podem ser resolvidos com um trabalho inteligente de ceifeira que verifica o tamanho do lixo e limpa as coisas periodicamente, semelhante a um tmpreaper . Pode ser uma tarefa cron, ou uma versão mais inteligente pode fazer uso das várias infraestruturas de eventos do sistema de arquivos disponíveis em muitas distribuições de desktop Linux. Isso não é simples e ainda mais difícil de ser feito com eficiência. É melhor encontrar um sistema existente do que tentar criar o seu próprio.

O quarto pode ser resolvido transformando seu novo rm em um alias de shell alias rm='trash'; portanto, ele não afetará os programas.

O quinto é um problema que deixo para o leitor resolver. O rm não possui muitos switches.

Schwern
fonte
Eu tenho um alias rm -i, mas geralmente uso \rmpara obter um comportamento sem alias . Eu digito a rm -iqualquer momento que estou planejando dizer não a um dos argumentos. Às vezes, inicio o comando com lso comando e só coloco o comando quando terminar. Portanto, não há como acidentalmente obter retorno em rm -rf /vez de/.../file
Peter Cordes
rm -Iou rm --interactive=onceé muito, muito menos irritante do que rm -i, e ainda pega aything perigosas (só prompts quando há mais de 3 arquivos, ou se é recursiva, e apenas uma vez, em vez de para cada arquivo.)
Nick Matteo
@ Kundor Sim, e isso não muda a equação. Provavelmente, torna mais provável que o usuário o ignore. O usuário tem um objetivo: excluir coisas. O prompt diz "você tem certeza de que deseja excluir as coisas que acabou de me dizer para excluir?" O usuário ainda está fixado no objetivo de excluir itens, sem verificar o que deve ser excluído; portanto, eles dizem "sim" sem pensar. -ipode dar ao usuário tempo para alterar metas. Esta resposta em uma pergunta relacionada explica tudo.
Schwern 15/01
@ Schwern: mas ninguém pode conviver rm -ipor mais de 30 segundos sem desligá-lo. Considerando que rm -Iapenas solicita quando é provável que você tenha estragado tudo; o prompt aparece apenas para grandes exclusões. Quando você estava tentando excluir algumas coisas e o aviso foi dado, você ficou surpreso e percebeu que digitou acidentalmente "foo *".
Nick Matteo
@Kundor A exclusão de mais de três arquivos e a exclusão recursiva (a confirmação é desativada pelo habitual -rfque acabei de descobrir) são proxies ruins para detectar um possível erro. Não é provável que você queira excluir um subdiretório. A mensagem não ajuda porque apenas confirma o que o usuário disse para fazer sem adicionar informações úteis em um momento em que o usuário não está procurando verificar. "rm: remove 1 argumento recursivamente?" "Sim, exclua o diretório, eu apenas lhe disse para fazer isso! ... espere, qual diretório era esse? EXCREMENTO !!!"
precisa saber é o seguinte
2

Eu ensino a todos sobre o !$argumento = last no último truque de comando:

% ls job[XYZ].*
jobX.out1
jobX.out2
[rest of the matches]

% rm !$

Isso permite uma inspeção da expansão do curinga e, em seguida, o uso exato do mesmo padrão glob sem a possibilidade de inserir um espaço antes do *.

Também sugiro que as pessoas nunca cortem e colem um padrão curinga brilhante em uma linha de comando potencialmente destrutiva. Porque nas minhas próprias mãos isso tem sido um problema :)

Um técnico em meu laboratório acabou de cometer esse erro na semana passada (3 meses de trabalho) - e sim, tivemos um backup (1 dia atrasado).

Kael
fonte
0

Todo mundo parece estar dizendo: "Seja mais cuidadoso", "Não faça um pedido de alias / confirmação, porque você se acostumará a não prestar a devida atenção a ele".

Legal, e tudo. Quero dizer, não acho que você deva criar um apelido para rm(nem rmrf, já que você pode facilmente estragar tudo e digitar o comando real).

Mas por que você não pode criar um apelido / script e chamá-lo, digamos, removee alimentá-lo apenas com um argumento (por exemplo, $ 1)? O curinga deve ser $ 2, por causa do espaço inadvertido (correto?) E, portanto, seu script / wrapper / alias não será alimentado pelo segundo. Sim, você pode fazer apenas um conjunto de exclusões (com um curinga) por vez, mas esse é o preço que você pagaria.

Se eu estivesse escrevendo algo legal, poderia me dizer o número de arquivos e diretórios que está planejando excluir e o tamanho total das coisas que eu estava excluindo e pedir uma confirmação, mas isso pode impedir seu fluxo. Talvez faça disso uma opção de sinalização remove? (-Eu). Você também pode verificar $ 1 para ver se é apenas um curinga e pedir uma confirmação, e listar em qual diretório você está.


Como um aparte, há uma série de rmsubstituições por aí. Muitos estão tentando ser compatíveis com o lixo da área de trabalho da interface do usuário. Alguns desses podem valer a pena investigar.

user3082
fonte
6
Seu alias "remover" nunca removerá mais de um arquivo por vez. Você não pode usar um curinga, porque o shell o expande antes que o comando o veja.
Hymie
Então faça uma avaliação e, em seguida, coloque isso no script?
usar o seguinte comando
Então você quer digitar remove \*? Se o seu script permite que o shell expanda sua entrada, não o vejo ajudando muito.
Peter Cordes
0

Um truque muito simples é colocar -rfno final: rm whatever* -rf
isso reduz drasticamente a taxa de erro, porque você digita mais caracteres após o *, para ter mais tempo para ver erros de digitação.
Isso não resolve tudo. Apenas um truque simples do dia a dia.

Gregory MOUSSAT
fonte