linux 在bash函数中,如何将stdin放入变量中

63lcw9qa  于 2023-06-29  发布在  Linux
关注(0)|答案(3)|浏览(132)

我想用管道调用一个函数,并将所有的stdin读入一个变量。
我读到正确的方法是使用read,或者read -rread -a。然而,我在实践中遇到了很多问题(尤其是多行字符串)。
最后我决定

function example () {
  local input=$(cat)
  ...
}

习惯做法是什么?

gdx19jrr

gdx19jrr1#

input=$(cat)是捕获标准输入的一种非常好的方法。需要注意的是,命令替换会删除所有尾随的换行符,因此如果您希望确保也捕获这些换行符,则需要确保最后读取除换行符之外的内容。

input=$(cat; echo x)
input=${input%x}   # Strip the trailing x

bash 4或更高版本中的另一个选项是使用readarray命令,该命令将用每行标准输入填充数组,每个元素一行,然后可以根据需要将其连接回单个变量。

readarray foo
printf -v foo "%s" "${foo[@]}"
gtlvzcf8

gtlvzcf82#

根据我运行的测试,我发现使用cat与下面的方法相比非常慢:

local input="$(< /dev/stdin)"

如果有人想知道,<只是输入重定向。来自bash-hackers wiki(*new link until fixed *):
当内部命令只是一个输入重定向,而没有其他内容时,例如

$( <FILE )
# or
` <FILE `

然后Bash尝试读取给定的文件,并在给定的命令是cat FILE时执行操作。

关于可移植性的说明

就这种方法的可移植性而言,你可能会在你的整个linux用户生涯中,从来没有使用过没有/dev/stdin的linux系统,但是如果你想满足这个愿望,这里有一个question on Unix Stackexchange,它质疑直接访问/dev/{stdin,stdout,stderr}和朋友的可移植性。
我在使用linux * 容器 *(例如使用docker或buildah构建的容器)时遇到的另一件事是,有些情况下/dev/stdin甚至/dev/stdout在容器中不可用。我还不能确定是什么原因造成的。

p4rjhz4m

p4rjhz4m3#

在SO上有一些重叠/非常相似的问题。我在这里使用read内置函数回答了这个问题:
https://stackoverflow.com/a/58452863/3220983
然而,在我的回答中,我只关心一行**。

**cat方法的一个有争议的缺点是需要生成一个子shell。**否则,这是一个很好的方法。这可能是处理多行处理的最简单的方法,就像这里特别询问的那样。

我认为read方法更快/更高效,如果你试图链接很多命令,或者反复遍历一个列表来调用一个函数。

相关问题