如何将输出重定向到shell中的变量?

mar*_*ial 186 bash shell

我有这样的剧本

genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5
Run Code Online (Sandbox Code Playgroud)

我想在变量中获取genhash生成的流.如何将其重定向到变量$hash以在条件内进行比较?

if [ $hash -ne 0 ]
  then echo KO
  exit 0
else echo -n OK
  exit 0
fi
Run Code Online (Sandbox Code Playgroud)

小智 315

使用$( ... )构造:

hash=$(genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5)
Run Code Online (Sandbox Code Playgroud)

  • 这会捕获命令的输出,但不会使用重定向.如果由于需求更复杂而确实需要使用重定向,请参阅我的回答.谷歌把你带到了这里,对吗?为什么去其他地方找到你搜索到的答案? (49认同)
  • @BrunoBronosky这对我有用:`result = $(($ your_command)2>&1)` (12认同)
  • 实际上不是OP问题的答案 (11认同)
  • @Kayvar 当您使用 `$( ... )` 时,它使用新的子 shell,因此命令的结果可能与主 shell 中的结果不同 (4认同)

Bru*_*sky 200

TL; DR

存储"abc"$foo:

echo "abc" | read foo
Run Code Online (Sandbox Code Playgroud)

但是,因为管道会产生叉子,所以必须$foo在管道末端之前使用,所以......

echo "abc" | ( read foo; date +"I received $foo on %D"; )
Run Code Online (Sandbox Code Playgroud)

当然,所有这些其他答案显示了不做OP所要求的方法,但这真的搞砸了我们其他人搜索OP的问题.

问题的答案是使用该read命令.

这是你如何做到的

# I would usually do this on one line, but for readability...
series | of | commands \
| \
(
  read string;
  mystic_command --opt "$string" /path/to/file
) \
| \
handle_mystified_file
Run Code Online (Sandbox Code Playgroud)

这是它正在做什么以及它为什么重要:

  1. 让我们假装这series | of | commands是一系列非常复杂的管道命令.

  2. mystic_command可以接受文件的内容作为stdin来代替文件路径,但不能接受--optarg因此它必须作为变量.该命令输出修改后的内容,通常会重定向到文件或管道传输到另一个命令.(例如sed,awk,perl等等)

  3. read 接受stdin并将其放入变量中 $string

  4. 通过括号将readmystic_command放入"子shell"不是必需的,但使其像连续管道一样流动,就好像2个命令在单独的脚本文件中一样.

总有一种替代方案,在这种情况下,与上面的例子相比,替代方案是丑陋且难以理解的.

# my example above as a oneliner
series | of | commands | (read string; mystic_command --opt "$string" /path/to/file) | handle_mystified_file

# ugly and unreadable alternative
mystic_command --opt "$(series | of | commands)" /path/to/file | handle_mystified_file
Run Code Online (Sandbox Code Playgroud)

我的方式完全是按时间顺序排列的.替代方案从第4个命令开始,并将命令1,2和3推送到命令替换中.

我在这个剧本中有一个真实世界的例子,但我没有用它作为上面的例子,因为它还有一些其他疯狂/混乱/分散注意力的bash魔法.

  • 如果你的stdin将有多行,你可以使用`read -d''string`. (5认同)
  • 我也相信这是正确的答案.在某些情况下,$(...)不起作用,而管道被接受. (3认同)
  • @RichardBronosky感谢您发布此答案.可以访问父进程中的变量(例如,在管道中更远,例如在`handle_mystified_file`部分)?这似乎是不可能的,因为`read`在子进程中运行,这不会影响父进程中的变量.我试图通过使用`tee`和"重新连接"`tee`-分割的进程来分割来自进程的输出,通过在另一个中读取一个作为参数的输出. (3认同)
  • @PhươngNguyễn,这不起作用,因为管道创建了流程叉.这是我不得不添加括号的另一个原因.`echo"test"| (阅读ROLE_X; echo $ ROLE_X)`在http://stackoverflow.com/a/13764018/117471上阅读更多关于此分叉的内容 (3认同)
  • 仍不适用于括号.`ls (读取$ x; echo $ x)`只打印ls输出的第一行.'read'不能读取多行输出. (3认同)

小智 58

read hash < <(genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5)
Run Code Online (Sandbox Code Playgroud)

这种技术使用Bash的" 进程替换 ",不要与" 命令替换 " 混淆.

以下是一些很好的参考:

  • 这需要更多的投票.这些日子里唯一对我有用的解决方案. (6认同)
  • 当子命令不能在子shell中运行时,这很有用.谢谢! (3认同)
  • 希望更多的人理解`&lt;(…)`的用法,这纯粹是太棒了。OP应该给出一个解释。基本上,它运行一个子进程,但不传递它,而是返回一个文件描述符。这使您可以在需要文件的地方使用命令。例如(以root用户身份)`vimdiff / etc / sysconfig / iptables &lt;(iptables-save)`最终打开了一个类似于`/ proc / 23565 / fd / 63`的文件名。是的,`vim`可以接受`-`作为文件名,并可以从`stdin`中读取,但这只是一个例子。可能事情不使用`-`或`&lt;()`允许的命令顺序更易读。 (2认同)
  • @IntrepidDude我编辑了答案,包括你(和其他人)需要知道的内容.谢谢你的询问.这将使每个人受益. (2认同)

ony*_*ony 18

我想兼容的方式:

hash=`genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5`
Run Code Online (Sandbox Code Playgroud)

但是我更喜欢

hash="$(genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5)"
Run Code Online (Sandbox Code Playgroud)

  • @Koshinae,它将尝试扩展“echo $hash”。但如果你执行 `hash=$(echo '*'0); ,它会保持 `*` 不变。回显“$哈希”` (2认同)

小智 6

如果管道太复杂而无法包装$(...),请考虑编写一个函数。定义时可用的任何局部变量都可访问。

function getHash {
  genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5
}
hash=$(getHash)
Run Code Online (Sandbox Code Playgroud)

http://www.gnu.org/software/bash/manual/bashref.html#Shell-Functions


cod*_*ict 5

你可以做:

hash=$(genhash --use-ssl -s $IP -p 443 --url $URL)
Run Code Online (Sandbox Code Playgroud)

或者

hash=`genhash --use-ssl -s $IP -p 443 --url $URL`
Run Code Online (Sandbox Code Playgroud)

如果要将整个管道的结果分配给变量,可以在上面的赋值中使用整个管道。