Gostaria que o shell me avisasse sobre possíveis erros que estou prestes a cometer.
Como posso evitar que um comando cmd2
seja 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 histverify
o que impediria que o histórico fosse expandido e executado em uma única etapa. Aqui, o acima $ rm !$
seria expandido para $ rm file.tar
na 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, bash
possui 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 3
no final), mas não pode quebrar o próximo comando por conta própria.
Se isso forrealmenteo que quiser, capture o DEBUG
sinal (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_COMMAND
para 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 rm
comando.
Em seus scripts de inicialização do shell (assumindo bash
, então ~/.bashrc
), você pode usar um alias rm
para -i
ou -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 root
quando 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.