向前然后向后输出每一行的命令

Ner*_*lek 6 linux bash zsh io-redirection

我正在寻找一个“元命令”xyz,这样:

(echo "foo"; echo "bar") | xyz rev
Run Code Online (Sandbox Code Playgroud)

将返回:

foo oof
bar rab
Run Code Online (Sandbox Code Playgroud)

我想避免使用临时文件,即我正在寻找比以下更简洁的解决方案:

tempfile=$(mktemp)
cat > $tempfile
cat $tempfile | rev | paste $tempfile -
Run Code Online (Sandbox Code Playgroud)

(当然,我想要一个通用的解决方案,对于任何命令,不仅仅是rev,您可以假设该命令为每个输入行只输出一行。)

Zsh 解决方案也是可以接受的。

Oh *_*ess 6

一个壳函数。这将适用于任何支持<<<here-strings 的shell ,包括 zsh 和 bash。

xyz() { 
    while read line
    do 
        printf "%s " "$line"
        "$@" <<<"$line"
    done
}
Run Code Online (Sandbox Code Playgroud)
$ (echo "foo"; echo "bar") | xyz rev
foo oof
bar rab
Run Code Online (Sandbox Code Playgroud)

  • 用户说他们希望避免使用临时文件。使用 here-string 将使 `bash` 创建一个包含该字符串的临时文件。 (4认同)
  • @OhMyGoodness,如果我没看错,这会为每一行启动一个新的 `rev` 副本或 whetever,因此它仅适用于在生成输出时仅查看当前行的命令。但不是绝对行号或周围行的内容影响输出的东西。 (3认同)
  • @JL2210:不在 [POSIX] 中(https://pubs.opengroup.org/onlinepubs/009695399/utilities/echo.html)。例如,在 `ash` 中你会得到:`-nE a`。我知道这个问题是关于 `bash` 和 `zsh`,但我同意 `printf` 更便携,应该在这里使用,或者几乎在任何地方使用,而不是 `echo`。 (2认同)

ica*_*rus 6

由于stdio缓冲的工作方式,在大多数情况下会出现很多问题。linux 的一种解决方法可能是使用该stdbuf程序并使用 coproc 运行命令,这样您就可以明确控制输出的交错。

下面假设命令在每一行输入后输出一行。

#!/bin/bash
coproc stdbuf -i0 -o0 "$@"
IFS=
while read -r in ; do
    printf "%s " "$in"
    printf "%s\n" "$in" >&${COPROC[1]}
    read -r out <&${COPROC[0]}
    printf "%s\n" "$out"
done
Run Code Online (Sandbox Code Playgroud)

如果需要更通用的解决方案,因为 OP 只要求程序的每一行输入最终输出一行而不是立即输出,则需要更复杂的方法。创建一个事件循环,read -t 0用于尝试从 stdin 和协进程读取,如果两者具有相同的“行号”,则输出,否则存储该行。如果在任何一轮事件循环中都没有准备好,为了避免使用 100% 的 cpu,然后在再次运行事件循环之前引入一个小的延迟。如果过程输出部分行,则存在额外的复杂性,这些需要缓冲。

如果需要这个更通用的解决方案,我会使用expect来编写它,因为它已经很好地支持处理多个输入流上的模式匹配。但是,这不是 bash/zsh 解决方案。