命令替换没有输出?

Ete*_*our 4 bash shell-script command-substitution

我写了一些 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
Run Code Online (Sandbox Code Playgroud)

这是从 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
    
    Run Code Online (Sandbox Code Playgroud)

为什么$VENDOR输出到日志文件时变量为空?

编辑:

这是从命令替换中删除重定向后的更新。

  • 添加了一行以将$VENDOR变量打印到终端。
  • 静态分配值而不是使用$DEVICE变量。

打印$VENDOR到终端输出错误,但它仍然没有附加到日志文件中!$DEVICE日志文件中IS的值。我相信它与命令替换中的输出重定向有关。

ilk*_*chu 7

在这里,如果lsusb丢弃错误,则不会重定向错误消息,只会重定向来自grep. 错误lsusb仍然是通常的stderr,即终端(或stderr脚本启动时的任何错误。

VENDOR=$(lsusb -D "$DEVICE" | grep idVendor 2>&1)
Run Code Online (Sandbox Code Playgroud)

例如

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

您需要将它们的两个输出作为一个组重定向,以便命令替换也捕获错误:

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

使用单独的重定向,例如$( foo 2>&1 | grep 2>&1 )将第一个命令的错误发送到管道,并进行grep过滤,在上面的示例中将再次产生空输出。