如何将多行 bash 命令重定向到变量中

如何将多行 bash 命令重定向到变量中

我想将此命令重定向到一个变量:

{
    printf 'scan on\n\n'
    sleep 10
    printf 'quit \n\n'  
} | bluetoothctl

我尝试这样做:

variable=$(printf 'scan on\n\n' sleep 10 printf 'quit \n\n' | bluetoothctl)
echo $variable

但我得到空白输出。我也尝试过拆分它:

variable=$(printf 'scan on\n\n' | bluetoothctl)
sleep 10
printf 'quit \n\n'| bluetoothctl
echo $variable

但这次我只得到

Agent registered
[bluetooth]# quit

如何将stdout运行时打印的第一个命令的输出重定向到变量中?

答案1

只是:

variable=$(
  {
    printf 'scan on\n\n'
    sleep 10
    printf 'quit \n\n'  
  } | bluetoothctl
)

命令替换的内部可以是任何 shell 代码1,并且不必位于一行。

在这里,您想要捕获整个管道的输出(实际上,这将是 的输出,bluetoothctl因为所有其他命令的 stdout 都重定向到转到 的管道bluetoothctl)。

您还可以使用以下命令捕获 only 的输出bluetoothctl

{
  printf 'scan on\n\n'
  sleep 10
  printf 'quit \n\n'  
} | variable=$(bluetoothctl)

但在 中bash,要使其工作,您需要为最后一个管道组件设置选项lastpipeshopt -s lastpipe,仅适用于非交互式 shell 实例)不是在子 shell 中运行。

然而,在这里,您不需要管道,您可以这样做:

variable=$(bluetoothctl --timeout 10 scan on)

如果要显示变量的内容,请记住语法是:

printf '%s\n' "$variable"

不是echo $variable

有关详细信息,请访问:

这里的输出bluetoothctl包含着色转义序列以及用于清除行内容的转义序列。如果不加引号$variable,其内容将受到 split+glob 的影响,从而产生要传递到的随机单词列表,echo该列表echo将以空格分隔输出。所以你最终会把所有的东西都写在一行上,如果最后一个单词以 a 结尾清晰的线条序列(它在我的测试中所做的\r\e[K回车符接下来是清晰到生产线末端序列),你只会看到一个空行。


1 尽管有些 shellbash用来阻塞带有不匹配括号的代码,例如当代码包含 case 语句case $x in foo)或不平衡的注释时),shell 解析器将其误认为是)关闭命令替换。

答案2

错误是缺少分号(否则相当于换行符)。如果您想查看输出的结构,请添加双引号。尝试:

variable=$( { printf 'scan on\n\n' ; sleep 10 ; printf 'quit \n\n' ; } | bluetoothctl)
echo "$variable"

答案3

一个可能的替代方案是一个简单的expect脚本:

#!/usr/bin/expect

spawn bluetoothctl

send "scan on\r"

sleep 10

send "quit \r"

expect eof

\r 等于“返回/按 Enter”。制作可执行文件并运行。

相关内容