私はいくつかのシェルスクリプトを記述しましたが、この動作を見たことがなく、途方に暮れています。 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
コマンドからの出力が含まれていません。
これが私が行ったデバッグです。
$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の値です。コマンド置換内の出力リダイレクトと関係があると思います。
ここで、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
でフィルター処理されます。上記の例では、空の出力が生成されます。