bash_history: comenta los comandos peligrosos: `#`

16

Para evitar el registro de comandos "peligrosos" en el historial de bash, he agregado la siguiente línea a mi .bashrcarchivo:

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

esto funciona bien, pero tiene un efecto secundario: no puedo ver el historial completo de los comandos ejecutados en una máquina. Digamos que tengo varias máquinas para experimentos, y quiero poder ver todos los comandos ejecutados. Usaría bash internal historypara mostrar los comandos ejecutados, y quizás grep para la fecha de hoy:

history | grep Sep-28

Lo que me gustaría tener también es registrar comandos "peligrosos", pero poner un #al principio de la línea, de modo que si ejecuto el comando desde el historial por error, no se producirá ningún daño.

No tengo idea si esto es posible.

Actualización y aclaración:

La razón principal por la que esto es un problema para mí es que generalmente estoy conectado a mi máquina desde varios terminales, y cualquier comando ejecutado en un terminal se lee inmediatamente en el historial de otros terminales. Esto se logra mediante

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

Imaginemos que tengo dos terminales abiertas. En uno tengo algún cat /dev/foo > file.outproceso en ejecución. En el segundo, verifico el progreso con ls -lAhF. Sigo repitiendo lspresionando Upy ENTER(es decir, el último comando del historial). Tan pronto como termina el primer comando, el último comando del historial ya no es ls, pero cat /dev/foo > file.out. Si no tengo cuidado, volveré a iniciar cat y sobrescribiré file.out.

Lo que me gustaría lograr es que el comando cat esté precedido por un #, para que no se ejecute. Sin embargo, todavía lo vería en la historia y puedo reutilizarlo (si es un comando largo) al descomentarlo.

Martin Vegter
fuente
En lugar de repetir su comando manualmente, puede usar watch ls -lAhFo while sleep 1; do ls -lAhf; done; en lugar de ver el tamaño del archivo, puede usar pv /dev/foo > file.out( ivarch.com/programs/pv.shtml ).
deltab

Respuestas:

9

Podrías hacer 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

La idea es que antes de cada solicitud, verifiquemos la última entrada del historial ( history 1) y, si es una de las más peligrosas , la eliminemos ( history -d) y la agreguemos de nuevo con un #con history -s.

(obviamente, debe eliminar su HISTIGNOREconfiguración).

Un efecto secundario no deseado de que aunque es que altera el tiempo de la historia de los que rm, mv... comandos.

Para arreglar eso, una alternativa podría 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

Esta vez, registramos la hora del último historial y, para volver a agregar la línea del historial, utilizamos history -run archivo temporal (el documento aquí) que incluye la marca de tiempo.

Desea fixhistque se realice antes de su history -a; history -c; history -r. Desafortunadamente, la versión actual de bashtiene un error que history -ano guarda esa línea adicional que hemos agregado. Una solución es escribirlo en su lugar:

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

Es agregar el comando comentado al HISTFILE nosotros mismos en lugar de dejar history -aque lo hagamos.

Stéphane Chazelas
fuente
¿puedes explicar qué cmd=${cmd#*[0-9] }hace? ¿Y dónde exactamente debo poner fixhistmi PROMPT_COMMAND? Por el momento, ya contienePROMPT_COMMAND="history -a; history -c; history -r"
Martin Vegter
¿Cuál es el papel de HISTTIMEFORMAT=/? Ya me he puesto export HISTTIMEFORMAT="%b-%d %H:%M ". Por cierto, cuando agrego su código en mi $HOME/.bashrc, no pasa nada.
Martin Vegter
HISTTIMEFORMAT=/es solo para esa invocación de historyobtener una salida como 123 /rm xdonde es más fácil extraer el cmd. Hubo un problema con algunas versiones de bashdonde $HISTCMDera falso en ese contexto, pruebe la nueva versión.
Stéphane Chazelas
todavía no funciona. Me pregunto, ¿ #el código no actúa como comentarios .bashrc?
Martin Vegter
1
@MartinVegter, sí, para entradas de historial modificadas , bashinserta un *después del número de historial que no se esperaba. Debería arreglarse ahora.
Stéphane Chazelas
11

No voy a responder exactamente su pregunta, pero tal vez le dé una solución alternativa a su problema.

Si entiendo correctamente, le preocupan los errores que podría cometer escribiendo, por ejemplo, !rmsi sucedió que el rmcomando anterior en el historial elimina algo que le gustaría conservar.

En este caso, una buena opción bash es histverify. Si usted shopt -s histverify, y recuerda un comando con la explosión !, no se ejecutará inmediatamente, sino que se cargará en la línea de lectura para que pueda decidir ejecutarlo o no, y esto también le brinda la posibilidad de editarlo.

Intentalo:

  • Sin 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
  • Con histverify:

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

    En este caso, tendrá el cursor al final de la línea, listo para iniciarlo nuevamente, o no, o editarlo.

Si te gusta esta opción, ponla en tu .bashrc:

shopt -s histverify
gniourf_gniourf
fuente