Почему эта команда gpg в скрипте ведет себя по-другому, если ее вставить в оболочку?

Почему эта команда gpg в скрипте ведет себя по-другому, если ее вставить в оболочку?

Вот скрипт, который симметрично шифрует/дешифрует файл с помощью двух различных симметричных шифров последовательно.

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

Когда я запускаю, ./doublecrypt dec /tmp/test.encryptedя получаю ошибки

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

Если я изменю линию

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

к

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

Он печатает

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

Если я скопирую и вставлю это в bash, то все запустится правильно.

Так почему же не работает, если я уберу echoи позволю скрипту bash оценить его напрямую, как в исходной форме?

Я использую Ubuntu Saucy, а моя оболочка — bash.

решение1

Короткий ответ: см.BashFAQ #50: Я пытаюсь поместить команду в переменную, но сложные случаи всегда терпят неудачу!.

Длинный ответ: у вас проблемы из-за порядка, в котором оболочка анализирует различные элементы командных строк; в частности, она расширяет ссылки на переменные (например, ${ERR}) примерно на полпути процесса — после того, как она уже разобралась с такими вещами, как кавычки, экранирования и перенаправления. В вашем случае важна часть с перенаправлениями: к тому времени, как оболочка расширяется ${ERR}до 2>/dev/null, она уже ищет перенаправления и не находит их, поэтому она просто рассматривает это 2>/dev/nullкак аргумент команды, а затем gpgотклоняет его как не имеющий смысла.

По сути, хранение команд (или элементов команд) в переменных — неправильный способ. Переменные предназначены для данных, а не для исполняемого кода. В этом случае вам было бы гораздо лучше использовать функции:

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

Обратите внимание, что я также заключил его $2в двойные кавычки, чтобы предотвратить передачу его значения во вторую половину процесса синтаксического анализа оболочки.

решение2

Попробуйте изменить $D $2 ${ERR} | $D - ${ERR}на:

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

Также используйте полный путь к вашей gpgпрограмме, например:

/usr/local/bin/gpg

Связанный контент