Evitar que un comando se ejecute después de otro comando

Evitar que un comando se ejecute después de otro comando

Me gustaría que el shell me advirtiera sobre posibles errores que estoy a punto de cometer.

¿Cómo puedo evitar cmd2que se ejecute un comando después de cmd1.

Por ejemplo:

$ tar tf file.tar
$ rm !$

Aquí, simplemente olvidé que enumeré el archivo en lugar de extraer su contenido.

Estoy buscando una solución genérica, que haga una elección basada en el nombre y el valor de retorno del comando anterior y en el comando actual.

Respuesta1

En bash puedes establecer shopt -s histverifyqué evitará que el historial se expanda y se ejecute en un solo paso. Aquí lo anterior $ rm !$se expandiría al $ rm file.tarpresionar por primera vez Enter, permitiéndole verificar o editar antes de presionar Enternuevamente para ejecutar.
Una solución más general se inclinaría hacia"Haz lo que quiero decir"territorio, lo que requiere un programa para cuestionar sus intenciones.

Respuesta2

Estás pidiendo mucho con una respuesta general, pero debería ser posible hacerlo con relativa facilidad hasta cierto punto.

Sin embargo, bashexisten al menos dos mecanismos generales que pueden ayudar a solucionarlo. Puede configurar la variable PROMPT_COMMAND y esto se ejecutará después de cualquier cosa que ejecute en su mensaje:

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

Podemos usar esto para guardar el último comando ingresado y luego volver a leerlo, de modo que podamos almacenarlo en la memoria para su uso posterior (la expansión del historial no funciona en este 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 .

Ahora viene la parte lógica, que depende completamente de ti. Usemos una lógica muy simplista para evitar el ejemplo de la pregunta. Lo que hay que recordar es que las funciones bash todavía funcionan allí, por lo que no es necesario meter todo en una sola línea, en una sola variable.

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

Por supuesto, este enfoque es útil para evitar PEBKAC (especialmente si lo agrega sleep 3al final), pero no puede interrumpir el siguiente comando por sí solo.

si eso esen realidadlo que quieras, atrapa la DEBUGseñal (por ejemplo trap 'echo "I am not deterministic, haha"' DEBUG), ya que se ejecuta de antemano. Tenga cuidado al combinar estos dos enfoques, ya que el resultado/acción se duplicará:

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

Para hacer que la trampa rompa un comando, tendrás que habilitar extdebug( shopt -s extdebug). Tampoco es necesario guardar y releer el historial constantemente, pero puede inspeccionarlo $BASH_COMMANDpara que el comando esté a punto de ejecutarse. Luego solo necesita asegurarse de que el verificador lógico devuelva 1 cuando detecte algo malo y 0 en caso contrario.

          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 
$

Respuesta3

En este caso, se beneficiaría de las advertencias de error del rmcomando.

En sus scripts de inicialización de shell (suponiendo bashque ~/.bashrc), puede utilizar un alias rmpara -io -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

La pregunta más genérica de "¿Cómo protejo mi sistema de mí mismo?" ha sidodiscutido antes. En una palabra,presta atención a lo que estás haciendoy solo ejecute comandos cuando rootsea necesario.

Respuesta4

En tu caso concreto yo haría:

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

Si desea verificar si hay errores y solo ejecutar el siguiente comando si el primero tuvo éxito

some_command && another_command

Aunque en su caso específico, el segundo comando aún se ejecutaría ya que no produjo ningún error a pesar de que no hizo lo que quería.

información relacionada