我rbenv
在机器上安装了(ruby 版本管理器),它的工作原理如下:
$ rbenv local
2.3.1
写信给标准输出我的 ruby 的本地版本。我想挽救这个版本并将其声明在变量中以便在其他场合重用。
$ declare -r RUBY_DEFINED_VERSION=$(rbenv local)
$ echo Using ruby version $RUBY_DEFINED_VERSION
Using ruby version 2.3.1
有用!
但我不想使用子外壳完成工作(使用$()
或``
)。我想用同样的壳我不想创建一个tmp文件来完成工作。
有没有办法做到这一点?
笔记: declare -r
不是强制性的,可以是简单的var=FOOBAR
。
答案1
有一个 hack,但我认为如果你需要循环使用它,它就有意义。
你可以cat
coproc
像这样打开:coproc CAT { cat; }
这将cat
在后台启动一个命令,并设置两个环境变量:CAT_PID
和CAT
。该CAT
变量是一个数组,其中包含STDOUT
和STDIN
(按此顺序)使用的文件描述符(管道)cat
。
因此,您可以执行将输出写入&${CAT[1]}
代表 的任何内容STDIN
,并使用内置命令read
设置从中读取的变量${CAT[0]}
是STDOUT
cat 的变量。
这是一个示例:
coproc CAT { cat; }
echo 123 >&${CAT[1]}
read myvar <&${CAT[0]}
去测试:
echo $myvar
123
使用后不要忘记阻止猫。您可以通过终止进程来做到这一点。
kill $CAT_PID
这对性能调优产生了很大的影响。
更新:bash
实现null
分隔字符串。所以在处理二进制数据时,read
确实很棘手。您可以一次读取LC_ALL=C read -r -n1 -d $'\0'
一个字节,然后 null 将是${REPLY}
变量上的空字符串。
答案2
使用 bash 你也可以这样做:
read a < <(echo hello)
echo "$a"
或者像这样:
shopt -s lastpipe
echo hello | read a
shopt -u lastpipe
echo "$a"
但你仍然必须启动一个将运行 ruby 的子进程,所以我真的不明白你想避免什么......
答案3
如果在 Linux 上,使用bash
5.1(或 zsh)之前的版本,您可以执行以下操作:
{
chmod u+w /dev/fd/3 # only needed in bash 5.0
rbenv local > /dev/fd/3
IFS= read -rd '' -u 3 variable
} 3<<< ''
这确实使用了像每个此处文档或此处字符串一样的临时文件,尽管它对您来说是隐藏的。
bash
5.1 改用管道而不是常规临时文件(至少当herefile/herestring 的内容足够小以适合管道缓冲区时)。有了这些,您始终可以手动创建临时文件:
tmpfile=$(mktemp) || exit
{
rm -f -- "$tmpfile"
rbenv local >&3
IFS= read -rd '' -u4 variable
} 3> "$tmpfile" 4< "$tmpfile"
<<
(像/ do一样尽早删除 tmpfile,以最大限度地减少脚本被杀死或退出 shell<<<
时留下的风险)。rbenv
如果rbenv
输出的数据少于管道中可以容纳的数据(通常为 64KiB),则仍然在 Linux 和仅 Linux 上,您可以使用管道代替临时文件:
{
rbenv local > /dev/fd/3
IFS= read -rd '' -u 3 variable
} 3< <(:)
对于ksh93
或最新版本mksh
,请使用不启动子 shell 的命令替换形式:
variable=${
rbenv local
}
目前,bash 和 zsh 的开发版本中也提供了该版本。
请注意,与该方法相反IFS= read -rd ''
,它会删除输出中的尾随换行符(就像常规命令替换一样)。
为了实现这一点,当前(截至 2024 年)版本的 ksh93 在内部使用预先删除的临时文件(在/dev/shm
我的 Debian 系统上)、mksh(在/tmp
我的系统上)、zsh-dev 相同,只是文件稍后被删除,并且bash-dev 匿名记忆力支持的地方有临时文件,不支持的地方有预先删除的临时文件/tmp
。
在旧版本中zsh
,您利用=(...)
进程替换的形式来获取自动删除的临时文件(此处作为参数传递给匿名函数):
() { rbenv local > $1; IFS= read -rd '' variable <$1; } =()
1 但就 zsh 而言,${ cmd }
目前正在争论是否这样做或仅在不加引号时这样做。