コマンド置換結果は出力されませんか?

コマンド置換結果は出力されませんか?

私はいくつかのシェルスクリプトを書きましたが、このような動作を見たことがなく、圧倒感を感じます。 Bashシェルで実行される次の簡単なスクリプトがあります。

LOGFILE="/var/log/constructor-events.txt"

SUBSYSTEM="$1"
DEVTYPE="$2"
DEVICE="$3"

VENDOR=$(lsusb -D "$DEVICE" | grep idVendor 2>&1)

REQUEST=$(cat <<EOF
{"data": {
    "action": "add",
    "port": {
        "type": "$SUBSYSTEM",
    },
    "drive": {
        "vendor_id": "$VENDOR",
    }
}}
EOF
)

printf "output: $VENDOR" >> $LOGFILE
printf "%s\n" "`date +%x\ %r\ %Z` $REQUEST"  >> $LOGFILE

これは udev ルールで行われます。 udevの位置パラメータには私が期待する値があり、それをログファイルに印刷するのに問題はありません。ただし、何らかの理由で変数にコマンドの出力は$VENDOR含まれません。lsusb

私が実行したデバッグは次のとおりです。

  • 発生する可能性のあるエラーをキャッチするために、stdoutにstderrリダイレクトを追加しました。
  • $VENDOR空のログに変数を直接送信する行を追加しました。
  • シェルでスクリプトを手動で実行し、$VENDOR変数を端末に印刷すると空です。
  • 変数に含まれる文字列を取得し$DEVICEてシェルから直接実行すると、次の結果が表示されます。

    [root@host ~]# lsusb -D /dev/bus/usb/016/030 | grep idVendor
    Cannot open /dev/bus/usb/016/030
    

$VENDORログファイルに出力するときに変数が空になるのはなぜですか?

編集する:

これは、コマンド置換からリダイレクトを削除した後の更新です。

  • $VENDOR端末に変数を印刷する行を追加しました。
  • 変数を使用する代わりに静的に値を割り当てます$DEVICE

$VENDORエラーを端末に印刷するとエラーが出力されますが、それでもログファイルに追加されません。$DEVICEログファイルのIS値。私はこれがコマンド置換の出力リダイレクトに関連していると思います。

答え1

ここでlsusbエラーが削除されると、エラーメッセージはリダイレクトされず、発生したエラーのみがリダイレクトされますgrep。端末(またはスクリプトが実行される場所)lsusbである一般的なコンテキストでエラーが発生し続けます。stderrstderr

VENDOR=$(lsusb -D "$DEVICE" | grep idVendor 2>&1)

例えば

$ blah=$(ls -l /nonexisting | grep foo 2>&1)
ls: cannot access '/nonexisting': No such file or directory
$ echo "blah: '$blah'"
blah: ''

コマンドの置き換えでもエラーをキャッチできるように、両方の出力をグループにリダイレクトする必要があります。

$ blah=$( { ls -l /nonexisting | grep foo; } 2>&1)
$ echo "blah: '$blah'"
blah: 'ls: cannot access '/nonexisting': No such file or directory'

別のリダイレクトを使用すると、$( foo 2>&1 | grep 2>&1 )最初のコマンドのエラーがパイプに送信され、フィルタリングされ、grep上記の例では空の出力が生成されます。

関連情報