Por que esse comando gpg em um script se comporta de maneira diferente quando é colado em um shell?

Por que esse comando gpg em um script se comporta de maneira diferente quando é colado em um shell?

Aqui está um script que criptografa/descriptografa simetricamente um arquivo com duas cifras simétricas diferentes em sequência.

#!/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

Quando executo ./doublecrypt dec /tmp/test.encryptedrecebo os erros

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

Se eu mudar a linha

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

para

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

Ele imprime

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

Se eu copiar e colar no bash, ele será executado corretamente.

Então, por que não funciona se eu remover echoe deixar o script bash avaliá-lo diretamente, como na forma original?

Estou executando o Ubuntu Saucy e o bash é meu shell.

Responder1

Resposta curta: vejaBashFAQ #50: Estou tentando colocar um comando em uma variável, mas os casos complexos sempre falham!.

Resposta longa: você está tendo problemas por causa da ordem em que o shell analisa vários elementos das linhas de comando; especificamente, ele expande referências de variáveis ​​(como ${ERR}) na metade do processo - depois de já ter lidado com coisas como aspas, escapes e redirecionamentos. No seu caso, é a parte dos redirecionamentos que importa: no momento em que o shell se expande ${ERR}para 2>/dev/null, ele já procurou por redirecionamentos e não encontrou nenhum, então ele apenas trata 2>/dev/nullcomo um argumento para o comando e depois gpgrejeita isso como sem sentido.

Basicamente, armazenar comandos (ou elementos de comando) em variáveis ​​é a maneira errada de fazer isso. Variáveis ​​são para dados, não para código executável. Nesse caso, seria muito melhor usar funções:

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

Observe que também coloquei $2aspas duplas, para evitar que seu valor seja submetido à segunda metade do processo de análise do shell.

Responder2

Tente mudar $D $2 ${ERR} | $D - ${ERR}para:

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

Além disso, use o caminho completo para o seu gpgprograma, por exemplo:

/usr/local/bin/gpg

informação relacionada