我是否可以避免使用 FIFO 文件加入 Bash 管道的末端以存储在当前 shell 中的变量中?



我有以下功能:

execIn ()
{
local STORE_INvar="${1}" ; shift
printf -v "${STORE_INvar}" '%s' "$( eval "$@" ; printf %s x ; )"
printf -v "${STORE_INvar}" '%s' "${!STORE_INvar%x}"
}

getFifo ()
{
local FIFOfile
FIFOfile="/tmp/diamondLang-FIFO-$$-${RANDOM}"
while [ -e "${FIFOfile}" ]
do
FIFOfile="/tmp/diamondLang-FIFO-$$-${RANDOM}"
done
mkfifo "${FIFOfile}"
echo "${FIFOfile}"
}

我想将管道末端的输出存储到一个变量中,就像在管道末尾的函数一样,但是,我发现在早期版本的 Bash 中唯一可行的方法是使用 mkfifo 制作临时 fifo 文件。 我希望使用文件描述符来避免创建临时文件。 所以,这有效,但并不理想:

设置:(在执行此操作之前,我需要将FIFO文件分配给可供其余进程使用的var)

$ FIFOfile="$( getFifo )"

我要保留的管道:

$ printf 'nn123n456n524n789nnn' | grep 2  # for e.g.

操作:(我现在可以添加)>${FIFOfile} &

$ printf 'nn123n456n524n789nnn' | grep 2 >${FIFOfile} &

注:注:需要用&-问题1背景:我[1] <PID_NO>输出到屏幕上。

实际坚持:

$ execIn SOME_VAR cat - <${FIFOfile}

问题 2:屏幕上出现更多噪音

[1]+  Done  printf 'nn123n456n524n789nnn' | grep 2 > ${FIFOfile}

问题3:我在流的开头丢失了空白,而不是像以前那样在最后丢失。

那么,我这样做的方式是否正确? 我确信必须有一种方法可以避免之后需要使用文件描述符清理的 FIFO 文件,但我似乎无法这样做,因为我无法将问题的任何一方分配给未附加到文件或 FIFO 文件的文件描述符。

我可以尝试解决我所拥有的问题,尽管为了使它正常工作,我想我需要预先建立一个可以拉入使用的 FIFO 文件池,否则我有一个在命令之前建立此文件的先决条件。 因此,由于许多原因,这远非理想。 如果有人能告诉我一个更好的方法,你会让我的日/周/月/生活:)

提前感谢...

从远古时代起,进程替换就在 bash 中可用。您绝对没有一个如此古老的版本以至于无法使用它。因此,根本不需要使用FIFO:

readToVar() { IFS= read -r -d '' "$1"; }
readToVar targetVar < <(printf 'nn123n456n524n789nnn')

您将观察到:

printf '%qn' "$targetVar"

。正确保留前导换行符和尾随换行符。


相比之下,在您无法承受丢失标准配置的用例中:

readToVar() { IFS= read -r -d '' "$1" <"$2"; }
readToVar targetVar <(printf 'nn123n456n524n789nnn')

如果你真的想通过管道连接到这个命令,愿意需要一个非常现代的bash,并且不介意与作业控制不兼容:

set +m            # disable job control
shopt -s lastpipe # in a pipeline, parent shell becomes right-hand side
readToVar() { IFS= read -r -d '' "$1"; }
printf 'nn123n456n524n789nnn' | grep 2 | readToVar targetVar

您声称在使用FIFO时遇到的问题实际上并不存在。将其放入脚本中,然后运行它:

#!/bin/bash
trap 'rm -rf "$tempdir"' 0 # cleanup on exit
tempdir=$(mktemp -d -t fifodir.XXXXXX)
mkfifo "$tempdir/fifo"
printf 'nn123n456n524n789nnn' >"$tempdir/fifo" &
IFS= read -r -d '' content <"$tempdir/fifo"
printf '%qn' "$content" # print content to console

您会注意到,在脚本中运行时,屏幕上没有打印"噪音",因为所有这些状态都显式绑定到作业控制,默认情况下在脚本中禁用作业控制。

您还会注意到,前导换行符和尾随换行符都正确表示。

一个想法,告诉我我疯了,可能是使用 !! 符号来抓取刚刚执行的行,例如,如果有一个命令可以终止管道并停止它实际执行,而就 shell 而言,仍然将其视为成功执行,我在想类似于true命令的东西, 然后我可以使用!!抓住那行并调用我现有的函数以使用进程替换或其他方式执行它。 然后我可以将其包装到别名中,如下所示: 我认为可以使用alias streamTo=' | true ; LAST_EXEC="!!" ; myNewCommandVariation <<<'这样:$ cmd1 | cmd2 | myNewCommandVariation THE_VAR_NAME_TO_SET别名中的<<

不是完整的答案,而是第一点:是否有充分的理由不使用mktemp来创建具有随机名称的新文件?据我所知,您的函数称为getFifo()并没有执行更多。

mktemp -u

将给你一个免费的新名称而不创建任何东西;然后你可以用这个名字使用mkfifo

最新更新