我已经编写了一些 shell 脚本,但从未见过这种行为,并且感到不知所措。我有以下在 bash shell 中运行的简单脚本:
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
命令的输出。
这是我完成的调试。
- 添加了 stderr 重定向到 stdout 以捕获可能发生的任何错误。
- 添加了将
$VENDOR
变量直接发送到日志的行,该日志为空。 - 在 shell 中手动执行脚本并将
$VENDOR
变量打印到终端,它是空的。 获取变量中包含的字符串
$DEVICE
并直接在 shell 中执行,得到以下结果。[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
过滤,在上面的示例中将再次产生空输出。