¿Por qué este comando gpg en un script se comporta de manera diferente cuando se pega en un shell?

¿Por qué este comando gpg en un script se comporta de manera diferente cuando se pega en un shell?

Aquí hay un script que cifra/descifra simétricamente un archivo con dos cifrados simétricos diferentes en secuencia.

#!/bin/bash

if [ "$#" -ne 2 ]; then
    echo "Arguments: enc|dec filename"
    exit
fi

E="gpg -o - --symmetric --cipher-algo"
D="gpg -o - --decrypt"
ERR="2>/dev/null"

if [ "$1" = "enc" ]; then
    $E AES $2 | $E TWOFISH -
elif [ "$1" = "dec" ]; then
    $D $2 ${ERR} | $D - ${ERR}
else
    echo "Arguments: enc|dec filename"
    exit
fi

Cuando ejecuto ./doublecrypt dec /tmp/test.encryptedme salen los errores

usage: gpg [options] --decrypt [filename]
usage: gpg [options] --decrypt [filename]

Si cambio la línea

$D $2 ${ERR} | $D - ${ERR}

a

echo "$D $2 ${ERR} | $D - ${ERR}"

se imprime

gpg -o - --decrypt /tmp/xenc 2>/dev/null | gpg -o - --decrypt - 2>/dev/null

Si copio y pego esto en bash, se ejecuta correctamente.

Entonces, ¿por qué no funciona si elimino echoy dejo que el script bash lo evalúe directamente, como en el formato original?

Estoy ejecutando Ubuntu Saucy y bash es mi shell.

Respuesta1

Respuesta corta: verBashFAQ #50: Estoy intentando poner un comando en una variable, ¡pero los casos complejos siempre fallan!.

Respuesta larga: tiene problemas debido al orden en que el shell analiza varios elementos de las líneas de comando; específicamente, expande las referencias variables (como ${ERR}) aproximadamente a la mitad del proceso, después de haber tratado cosas como comillas, escapes y redirecciones. En su caso, lo que importa es la parte de redirecciones: cuando el shell se expande ${ERR}a 2>/dev/null, ya buscó redirecciones y no encontró ninguna, por lo que simplemente lo trata 2>/dev/nullcomo un argumento para el comando y luego gpglo rechaza por no tener sentido.

Básicamente, almacenar comandos (o elementos de comando) en variables es la forma incorrecta de hacerlo. Las variables son para datos, no para código ejecutable. En este caso, sería mucho mejor que usaras funciones:

e() {
    gpg -o - --symmetric --cipher-algo "$@"
}
d() {
    gpg -o - --decrypt "$@" 2>/dev/null
}

if [ "$1" = "enc" ]; then
    e AES "$2" | e TWOFISH -
elif [ "$1" = "dec" ]; then
    d "$2" | d -
else
    echo "Arguments: enc|dec filename"
    exit
fi

Tenga en cuenta que también lo puse $2entre comillas dobles para evitar que su valor quede sujeto a la segunda mitad del proceso de análisis del shell.

Respuesta2

Intente cambiar $D $2 ${ERR} | $D - ${ERR}a:

$( $D $2 ${ERR} | $D - ${ERR} )

Además, utilice la ruta completa a su gpgprograma, por ejemplo:

/usr/local/bin/gpg

información relacionada