bash_history: comente os comandos perigosos: `#`


16

Para evitar o registro de comandos "perigosos" no histórico do bash, adicionei a seguinte linha ao meu .bashrcarquivo:

HISTIGNORE='rm *:mv *:cp *:cat*>*:pv*>*'

isso funciona bem, mas tem um efeito colateral: não consigo ver o histórico completo dos comandos executados em uma máquina. Digamos que tenho várias máquinas para experimentos e quero poder ver todos os comandos executados. Eu usaria o bash internal historypara exibir comandos executados e talvez grep para a data de hoje:

history | grep Sep-28

O que eu gostaria de ter é registrar também comandos "perigosos", mas coloque um #no início da linha, para que, se eu executar o comando do histórico por engano, nenhum dano será causado.

Não tenho ideia se isso é possível.

Atualização e esclarecimento:

A principal razão pela qual isso é um problema para mim é que geralmente estou conectado à minha máquina a partir de vários terminais, e qualquer comando executado em um terminal é imediatamente lido no histórico de outros terminais. Isso é alcançado por

PROMPT_COMMAND="history -a; history -c; history -r"

Vamos imaginar que tenho dois terminais abertos. Em um, tenho algum cat /dev/foo > file.outprocesso em execução. No segundo, verifico o progresso com ls -lAhF. Continuo repetindo lspressionando Upe ENTER(ou seja, o último comando da história). Assim que o primeiro comando termina, o último comando do histórico não é mais ls, mascat /dev/foo > file.out . Se não tomar cuidado, vou iniciar o gato novamente e sobrescrever file.out.

O que eu gostaria de conseguir é que o comando cat seja precedido por a #, para que não seja executado. No entanto, eu ainda o veria na história e posso reutilizá-lo (se for um comando longo) sem comentar.


Em vez de repetir seu comando manualmente, você pode usar watch ls -lAhFor while sleep 1; do ls -lAhf; done; em vez de observar o tamanho do arquivo, você pode usar pv /dev/foo > file.out( ivarch.com/programs/pv.shtml ).
Deltab 12/03/14

Respostas:


9

Você poderia fazer algo como:

fixhist() {
   local cmd histnum
   cmd=$(HISTTIMEFORMAT=/ history 1)
   histnum=$((${cmd%%[*/]*}))
   cmd=${cmd#*/} # remove the histnum
   case $cmd in
     (rm\ *|mv\ *|...)
       history -d "$histnum" # delete
       history -s "#$cmd"    # add back with a #
   esac
}
PROMPT_COMMAND=fixhist

A idéia é que antes de cada prompt, vamos verificar a última entrada do histórico ( history 1) e se é uma das perigosas queridos, nós excluí-lo ( history -d) e adicioná-lo de volta com um #com history -s.

(obviamente, você precisa remover sua HISTIGNOREconfiguração).

Um efeito colateral indesejado de que, porém, é que ele altera o tempo a história daqueles rm, mv... comandos.

Para consertar isso, uma alternativa poderia ser:

fixhist() {
   local cmd time histnum
   cmd=$(HISTTIMEFORMAT='<%s>' history 1)
   histnum=$((${cmd%%[<*]*}))
   time=${cmd%%>*}
   time=${time#*<}
   cmd=${cmd#*>}
   case $cmd in
     (rm\ *|mv\ *|...)
       history -d "$histnum" # delete
       HISTFILE=/dev/stdin history -r <<EOF
#$time
#$cmd
EOF
   esac
}
PROMPT_COMMAND=fixhist

Desta vez, registramos a hora do último histórico e, para adicionar novamente a linha do histórico, usamos history -rum arquivo temporário (o documento aqui) que inclui o registro de data e hora.

Você quer que o fixhistseja realizado antes do seu history -a; history -c; history -r. Infelizmente, a versão atual de bashum bug history -anão salva a linha extra que adicionamos. Uma solução é escrevê-lo:

fixhist() {
   local cmd time histnum
   cmd=$(HISTTIMEFORMAT='<%s>' history 1)
   histnum=$((${cmd%%[<*]*}))
   time=${cmd%%>*}
   time=${time#*<}
   cmd=${cmd#*>}
   case $cmd in
     (rm\ *|mv\ *|...)
       history -d "$histnum" # delete
       history -a
       [ -f "$HISTFILE" ] && printf '#%s\n' "$time" "$cmd" >> "$HISTFILE";;
     (*)
       history -a
   esac
   history -c
   history -r
}
PROMPT_COMMAND=fixhist

Isso é anexar o comando comentado ao HISTFILE em vez de deixá- history -alo.


você pode explicar o que cmd=${cmd#*[0-9] }faz? E onde exatamente eu devo colocar fixhistna minha PROMPT_COMMAND? No momento, ele já contémPROMPT_COMMAND="history -a; history -c; history -r"
Martin Vegter

qual é o papel HISTTIMEFORMAT=/? Eu já defini export HISTTIMEFORMAT="%b-%d %H:%M ". A propósito, quando adiciono seu código ao meu $HOME/.bashrc, nada acontece.
Martin Vegter

HISTTIMEFORMAT=/é apenas para essa chamada de historyobter uma saída como 123 /rm xonde é mais fácil extrair o cmd. Houve um problema com algumas versões de bashonde $HISTCMDera falso nesse contexto, tente a nova versão.
Stéphane Chazelas

ainda não funciona. Eu estou querendo saber, não o #no código não agir como comentários em .bashrc?
Martin Vegter

1
@MartinVegter, sim, por modificados entradas do histórico, bashinsere um *após o número história que não era esperado. Deve ser corrigido agora.
Stéphane Chazelas

11

Não vou responder exatamente à sua pergunta, mas talvez lhe dê uma solução alternativa para o seu problema.

Se bem entendi, você está preocupado com os erros que pode cometer digitando, por exemplo, !rmse o rmcomando anterior no histórico remover algo que você gostaria de manter.

Nesse caso, é uma boa opção do bashhistverify . Se você shopt -s histverify, e se você chamar um comando com o estrondo !, ele não será executado imediatamente, mas será carregado na linha de leitura para que você possa decidir executá-lo ou não, e isso também lhe dará a possibilidade de editá-lo.

Tente:

  • Sem histverify:

    $ touch some_foo
    $ rm some_foo
    $ touch some_foo
    $ !rm
    rm some_foo
    $ # oooops in fact I'd've like to keep it this time
  • Com histverify:

    $ shopt -s histverify
    $ touch some_foo
    $ rm some_foo
    $ touch some_foo
    $ !rm
    $ rm some_foo <cursor here>

    Nesse caso, você terá o cursor no final da linha, pronto para iniciá-lo novamente - ou não - ou para editá-lo.

Se você gosta dessa opção, coloque-a no seu .bashrc:

shopt -s histverify
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.