スクリプト内のこの gpg コマンドは、シェルに貼り付けると動作が異なるのはなぜですか?

スクリプト内のこの gpg コマンドは、シェルに貼り付けると動作が異なるのはなぜですか?

以下は、2 つの異なる対称暗号を順番に使用してファイルを対称的に暗号化/復号化するスクリプトです。

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

関連情報