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_PID和CAT. 该CAT变量是一个数组,其中包含STDOUT和STDIN(按此顺序)使用的文件描述符(管道)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}变量上的空字符串。
使用 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 的子进程,所以我真的不明白你想避免什么......
如果在 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 '',它会删除输出中的尾随换行符(与所有命令替换一样)。