如何使管道等待文件结束或在出错后停止?

Sen*_*nha 12 scripting pipe shell-script

在观看有关管道恶作剧的视频后,我尝试了以下命令。

man -k . | dmenu -l 20 | awk '{print $1}' | xargs -r man -Tpdf | zathura -
Run Code Online (Sandbox Code Playgroud)

它基本上将联机帮助页列表打印到 dmenu 供用户选择其中一个,然后使用 xargs 运行man -Tpdf %(从 xargs 的输入打印到标准输出联机帮助页 git 的 pdf)并将 pdf 传递给 pdf 阅读器(zathura )。

问题是(如您在视频中看到的)pdf 阅读器甚至在我在 dmenu 中选择一个联机帮助页之前就已启动。如果我单击 Esc 并选择无,则 pdf 阅读器仍处于打开状态,根本不显示任何文档。

如何使 pdf 阅读器(以及管道链中的任何其他命令)仅在其输入到达文件结尾或接收到输入时才运行?或者,或者,在链接的命令之一返回非零退出状态后,如何使管道链停止(以便如果 dmenu 返回未选择选项的错误,则不会运行以下命令)?

Kam*_*ski 13

如何使 pdf 阅读器(以及管道链中的任何其他命令)仅在其输入到达文件结尾或接收到输入时才运行?

ifne(在 Debian 中它在moreutils包中):

ifne 当且仅当标准输入不为空时运行以下命令。

在你的情况下:

… | ifne zathura -
Run Code Online (Sandbox Code Playgroud)


Kus*_*nda 6

管道中的所有命令几乎同时启动。只有通过管道的 I/O 才能同步它们。此外,管道只能保存管道缓冲区允许的信息。

因此,您无法避免运行管道的一个阶段,因为

  1. 无论如何,一旦所有其他阶段启动,该阶段中的命令就会启动,并且
  2. 如果命令没有消耗通过管道传入的输入,它将阻塞管道的前几阶段。

相反,在让管道完成的同时将输出写入文件。然后使用该文件。

示例(作为带一个参数的函数):

myman () {
    tmpfile=$( mktemp )

    if man -k "$1" | dmenu -l 20 | awk '{print $1}' | xargs -r man -Tpdf >"$tmpfile" && [ -s  "$tmpfile" ]
    then
        zathura "$tmpfile"
    fi

    rm -f "$tmpfile"
}
Run Code Online (Sandbox Code Playgroud)

zathura如果管道失败(xargs部分返回非零)或生成的文件为空,这也不会运行程序。

bashshell 中,您可能还想设置pipefailshell 选项set -o pipefail以让管道返回管道中失败的第一个命令的退出状态。你会想要创建tmpfile变量local

myman () {
    local tmpfile=$( mktemp )

    if [ -o pipefail ]; then
        set -o pipefail
        trap 'set +o pipefail' RETURN
    fi

    if man -k "$1" | dmenu -l 20 | awk '{print $1}' | xargs -r man -Tpdf >"$tmpfile"
    then
        zathura "$tmpfile"
    fi

    rm -f "$tmpfile"
}
Run Code Online (Sandbox Code Playgroud)

这会设置pipefail函数持续时间的选项(如果尚未设置),然后在需要时取消设置。它摆脱了-s对输出文件的测试。

  • @terdon 我正在考虑过早删除临时文件的情况。如果文件已经被删除,`rm -f` 不会出错(可能是由 `zathura` 删除,我不知道)。 (2认同)

mos*_*svy 6

PDF 文件应该是可查找的;任何 pdf 查看器都必须首先查看预告片,然后从那里跳转到外部参照表的偏移量。

由于管道不可搜索,zathura因此使用了一种混淆技巧,它将所有输入复制到一个临时文件中,然后像往常一样使用该临时文件。这种“聪明”的伎俩正在制造虚假的希望,并导致人们认为 pdf 文件是可流式传输的。

但是不管怎么说,zathura确实等待EOF显示文档之前,您不必为实现这一目标hapen做任何事情:

(sleep 10; cat file.pdf) | zathura -
# will really show the content of file.pdf after 10 seconds
Run Code Online (Sandbox Code Playgroud)

问题是,zathura如果文件正常,则无法选择仅打开窗口,如果情况不是这样,则退出并显示错误 - 它只会留在那里,好像一切正​​常:

$ dd if=file.pdf bs=50000 count=1 status=none | zathura -
error: could not open document  # its window still hanging around showing nothing

$ echo $?
0  # really?
Run Code Online (Sandbox Code Playgroud)

因此,即使您自己将输出重定向到临时文件,并且仅zathura在一切正常的情况下才运行,也不能保证如果zathura出于某种原因不喜欢输出,用户将不会看到黑色窗口.


顺便提一句,

man -X man
Run Code Online (Sandbox Code Playgroud)

将在带有 的 X11 窗口中显示联机帮助页gxditview,即使它看起来直接来自 '70 ;-)

而且,当然,您始终可以使用:

... | xargs xterm -e man
Run Code Online (Sandbox Code Playgroud)

除了许多其他增强功能外,它还可以让您在搜索和正确的文本选择中使用正则表达式。


归档时间:

查看次数:

1526 次

最近记录:

4 年,11 月 前