AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 515862
Accepted
Seninha
Seninha
Asked: 2019-04-28 04:48:06 +0800 CST2019-04-28 04:48:06 +0800 CST 2019-04-28 04:48:06 +0800 CST

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

  • 772

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

man -k . | dmenu -l 20 | awk '{print $1}' | xargs -r man -Tpdf | zathura -

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

问题是(正如您在视频中看到的那样)pdf 阅读器甚至在我在 dmenu 中选择一个联机帮助页之前就开始了。如果我单击 Esc 并选择无,pdf 阅读器仍然打开,根本没有显示任何文档。

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

shell-script scripting
  • 3 3 个回答
  • 2131 Views

3 个回答

  • Voted
  1. Best Answer
    Kamil Maciorowski
    2019-04-28T12:26:06+08:002019-04-28T12:26:06+08:00

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

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

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

    在你的情况下:

    … | ifne zathura -
    
    • 13
  2. Kusalananda
    2019-04-28T05:10:31+08:002019-04-28T05:10:31+08:00

    管道中的所有命令几乎同时启动。只有管​​道上的 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"
    }
    

    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"
    }
    

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

    • 6
  3. mosvy
    2019-04-28T07:44:51+08:002019-04-28T07:44:51+08:00

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

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

    但无论如何,在显示文档之前zathura确实会等待 EOF,您无需为此做任何事情:

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

    问题是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?
    

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


    顺便提一句,

    man -X man
    

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

    而且,当然,您总是可以使用:

    ... | xargs xterm -e man
    

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

    • 6

相关问题

  • 打印文件行及其长度的脚本[关闭]

  • 根据其中的值批量重命名(附加)CSV 文件

  • 通过命令的标准输出以编程方式导出环境变量[重复]

  • 按分隔符拆分并连接字符串问题

  • MySQL Select with function IN () with bash array

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve