捕获没有子shell的shell函数的输出

dgm*_*ike 10 shell command-substitution subshell variable

rbenv在机器上安装了(ruby 版本管理器),它的工作原理是这样的:

$ rbenv local
2.3.1
Run Code Online (Sandbox Code Playgroud)

写入标准输出我的 ruby​​ 的本地版本。我想拯救这个版本并在一个变量中声明它以在另一个场合重用。

$ declare -r RUBY_DEFINED_VERSION=$(rbenv local)
$ echo Using ruby version $RUBY_DEFINED_VERSION
Using ruby version 2.3.1
Run Code Online (Sandbox Code Playgroud)

有用!

但我不想使用子外壳来完成工作(使用$()``)。我想使用相同的外壳,我不想创建一个tmp文件来完成这项工作。

有没有办法做到这一点?

注意: declare -r不是强制性的,它可以是一个简单的var=FOOBAR.

ton*_*ton 11

有一个 hack,但我认为如果你需要循环使用它才有意义。

你可以cat coproc像这样打开一个:coproc CAT { cat; }

这将cat在后台启动一个命令,并设置两个环境变量:CAT_PIDCAT. 该CAT变量是一个数组,其中包含STDOUTSTDIN(按此顺序)使用的文件描述符(管道)cat

所以,你可以执行任何写输出&${CAT[1]}表示STDIN,并使用内置命令read来设置变量指数从${CAT[0]}那就是STDOUT猫。

这里有一个示例:

coproc CAT { cat; }
echo 123 >&${CAT[1]}
read myvar <&${CAT[0]}
Run Code Online (Sandbox Code Playgroud)

去测试:

echo $myvar
123
Run Code Online (Sandbox Code Playgroud)

使用后不要忘记停止猫。你可以通过杀死进程来做到这一点。

kill $CAT_PID
Run Code Online (Sandbox Code Playgroud)

这在性能调优方面有很大的不同。

更新:bash实现字符串null分隔。所以在处理二进制数据时,read真的很棘手。您可以一次读取LC_ALL=C read -r -n1 -d $'\0'一个字节,然后 null 将是${REPLY}变量上的空字符串。

  • `IFS= read -r -d $'\0' myvar` 读取空分隔数据 (2认同)

Vou*_*uze 5

使用 bash 你也可以这样做:

read a < <(echo hello)
echo "$a"
Run Code Online (Sandbox Code Playgroud)

或者像这样:

shopt -s lastpipe
echo hello | read a
shopt -u lastpipe
echo "$a"
Run Code Online (Sandbox Code Playgroud)

但你仍然必须启动一个将运行 ruby​​ 的子进程,所以我真的不明白你想避免什么......

  • 您的第一个方法有一个子 shell,破坏了变量赋值。所以 `read a &lt; &lt;(foo=bar; echo baz); echo "$a:$foo"` 输出 `baz:` 而不是 `baz:bar`。您的第二种方法不会更改 `$a` 的值。也许“shopt -u lastpipe”对我来说已经坏了? (2认同)

Sté*_*las 5

如果在 Linux 上,bash版本早于 5.1,您可以执行以下操作:

{
  chmod u+w /dev/fd/3 # only needed in bash 5.0
  rbenv local > /dev/fd/3
  IFS= read -rd '' -u 3 variable
} 3<<< ''
Run Code Online (Sandbox Code Playgroud)

这确实使用了像每个此处文档或此处字符串一样的临时文件,尽管它对您来说是隐藏的。bash5.1 改用管道而不是常规临时文件。

如果rbenv输出的数据少于管道中可以容纳的数据(通常为 64KiB),则仍然在 Linux 和仅 Linux 上,您可以使用管道代替临时文件:

{
  rbenv local > /dev/fd/3
  IFS= read -rd '' -u 3 variable
} 3< <(:)
Run Code Online (Sandbox Code Playgroud)

对于ksh93或最新版本mksh,请使用不启动子 shell 的命令替换形式:

variable=${
  rbenv local
}
Run Code Online (Sandbox Code Playgroud)

请注意,与 , 相反IFS= read -rd '',它会删除输出中的尾随换行符(与所有命令替换一样)。