bash_history: comente comandos perigosos: '#'

15

Para impedir o registro de comandos "perigosos" no histórico bash, adicionei a seguinte linha ao meu arquivo .bashrc :

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 eu tenha várias máquinas para experimentos e quero poder ver todos os comandos executados. Eu usaria o bash% history interno para exibir comandos executados e talvez grep para a data de hoje:

history | grep Sep-28

O que eu gostaria de ter é registrar os comandos "perigosos" também, mas colocar um # no começo da linha, de modo que se eu executar o comando do histórico por engano, nenhum dano seria feito.

Eu não tenho ideia se isso é possível.

Atualização e esclarecimento:

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

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

Vamos imaginar que tenho dois terminais abertos. Em um deles, tenho um processo de cat /dev/foo > file.out em execução. Na segunda, eu verifico o progresso com ls -lAhF . Eu continuo repetindo ls pressionando Up e ENTER (isto é, último comando do histórico). Assim que o primeiro comando terminar, o último comando do histórico não será mais ls , mas cat /dev/foo > file.out . Se eu não tiver cuidado, vou começar o gato novamente e sobrescrever arquivo.out.

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

    
por Martin Vegter 28.09.2013 / 10:28

2 respostas

9

Você pode 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, verificamos a última entrada do histórico ( history 1 ) e se é uma das perigosas , nós a deletamos ( history -d ) e a adicionamos de volta com um # com history -s .

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

Um efeito colateral indesejado disso é que ele altera o tempo do histórico dos comandos rm , mv ...

Para corrigir 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 de volta a linha do histórico, usamos history -r de um arquivo temporário (o documento do here) que inclui o timestamp.

Você deseja que o fixhist seja executado antes do seu history -a; history -c; history -r . Infelizmente, a versão atual de bash tem um erro em que history -a nã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 é para acrescentar o comando comentado ao HISTFILE em vez de deixar history -a fazer isso.

    
por 19.01.2014 / 22:22
11

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

Se eu entendi corretamente, você está preocupado com os erros que você pode cometer ao digitar, por exemplo, !rm se o comando anterior rm no histórico remover algo que você gostaria de manter.

Nesse caso, uma boa opção bash é histverify . Se você shopt -s histverify , e se você chamar um comando com o% bang_de%, 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 dá a possibilidade para editá-lo.

Experimente:

  • Sem ! :

    $ 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>
    

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

Se você gostou dessa opção, coloque-a em histverify :

shopt -s histverify
    
por 28.09.2013 / 14:57