Impedir que um comando seja executado após outro comando

Impedir que um comando seja executado após outro comando

Gostaria que o shell me avisasse sobre possíveis erros que estou prestes a cometer.

Como posso evitar que um comando cmd2seja executado após o cmd1.

Por exemplo:

$ tar tf file.tar
$ rm !$

Aqui, esqueci que listei o arquivo em vez de extrair seu conteúdo.

Estou procurando uma solução genérica, que faça uma escolha com base no nome e no valor de retorno do comando anterior e no comando atual.

Responder1

No bash você pode definir shopt -s histverifyo que impediria que o histórico fosse expandido e executado em uma única etapa. Aqui, o acima $ rm !$seria expandido para $ rm file.tarna primeira pressão de Enter, permitindo que você verifique ou edite antes de pressionar Enternovamente para executar.
Uma solução mais geral desviar-se-ia para"Faça o que eu quero dizer"território, exigindo um programa para adivinhar suas intenções.

Responder2

Você está pedindo muito com uma resposta geral, mas deve ser possível fazê-lo com relativa facilidade até certo ponto.

Porém, bashpossui pelo menos dois mecanismos gerais que podem ajudar a resolver isso. Você pode definir a variável PROMPT_COMMAND e ela será executada após qualquer execução no seu prompt:

$ PROMPT_COMMAND='echo BOFH says hi!'
BOFH says hi!
$ man man
BOFH says hi!
$

Podemos usar isso para salvar o último comando digitado e depois relê-lo, para que possamos armazená-lo na memória para uso posterior (a expansão do histórico não funciona neste caso):

$ PROMPT_COMMAND='history -a; tail -n1 ~/.bash_history'
PROMPT_COMMAND='history -a; tail -n1 ~/.bash_history'
$ wc < test.sh | grep .
 5 11 63
wc < test.sh | grep .

Agora vem a parte lógica, que depende totalmente de você. Vamos usar uma lógica muito simplista para evitar o exemplo da questão. O que devemos lembrar é que as funções bash ainda funcionam lá, então você não precisa amontoar tudo em uma única linha, em uma única variável.

$ # define the logic check
$ checkSanity() { grep -q "tar  *[tf][[:alpha:]]*[tf] " <<< "$@" && echo "be careful, don't delete this"; }
checkSanity() { grep -q "tar  *[tf][[:alpha:]]*[tf] " <<< "$@" && echo "be careful, don't delete this"; }
$ # feed it the last command
$ PROMPT_COMMAND='history -a; last=$(tail -n1 ~/.bash_history); checkSanity "$last"'
$ # simple test
$ tar tf test.sh 2>/dev/null 
be careful, don't delete this
$ tar xf test.sh 2>/dev/null 
$

Claro, esta abordagem é útil para evitar PEBKAC (especialmente se você adicionar sleep 3no final), mas não pode quebrar o próximo comando por conta própria.

Se isso forrealmenteo que quiser, capture o DEBUGsinal (ex. trap 'echo "I am not deterministic, haha"' DEBUG), já que ele roda antecipadamente. Tenha cuidado ao combinar essas duas abordagens, pois o resultado/ação será duplicado:

$ df
/.../
$ trap 'tail -n1 ~/.bash_history' DEBUG
df
df
trap 'tail -n1 ~/.bash_history' DEBUG
trap 'tail -n1 ~/.bash_history' DEBUG

Para fazer a armadilha quebrar um comando, você terá que habilitar extdebug( shopt -s extdebug). Você também não precisa salvar e reler o histórico constantemente, mas pode inspecionar $BASH_COMMANDpara que o comando esteja prestes a ser executado. Então você só precisa garantir que o verificador lógico retorne 1 quando detectar algo ruim e 0 caso contrário.

          extdebug
                  If set, behavior intended for use by debuggers is enabled:
    /.../
                  2.     If  the command run by the DEBUG trap returns a non-zero value, the next
                         command is skipped and not executed.


$ checkSanity() { if grep -q "tar  *[tf][[:alpha:]]*[tf] " <<< "$1"; then  echo "be careful, don't delete this"; return 1; fi; }
$ trap 'checkSanity "$BASH_COMMAND"' DEBUG
$ # simple test
$ tar tf test.sh 2>/dev/null 
be careful, don't delete this
$ tar xf test.sh 2>/dev/null 
$

Responder3

Nesse caso, você se beneficiaria com avisos de erro do rmcomando.

Em seus scripts de inicialização do shell (assumindo bash, então ~/.bashrc), você pode usar um alias rmpara -iou -I.

alias rm="rm -i"

Deman 1 rm

   -i     prompt before every removal

   -I     prompt once before removing more than three files, or when
          removing recursively.  Less intrusive than -i, while still
          giving protection against most mistakes

A questão mais genérica de “Como posso proteger meu sistema de mim mesmo” foidiscutido antes. Em poucas palavras,preste atenção no que você está fazendoe execute comandos apenas rootquando necessário.

Responder4

No seu caso específico, eu faria:

tar tf file.tar
if [ -f file ]; then   # Assuming you meant to extract a file
  rm -f file.tar
else
  echo "file is missing. Command failed."
fi

Se você deseja verificar se há erros e executar o próximo comando apenas se o primeiro for bem-sucedido

some_command && another_command

Embora no seu caso específico, o segundo comando ainda seja executado, pois não ocorreu nenhum erro, mesmo que não tenha feito o que você queria.

informação relacionada