私はいくつかのシェルスクリプトを書きましたが、このような動作を見たことがなく、圧倒感を感じます。 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
である一般的なコンテキストでエラーが発生し続けます。stderr
stderr
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
上記の例では空の出力が生成されます。