bash 进程替换和尾部结果不正确?

2024-01-29

使用 bash 进程替换,我想同时在一个文件上运行两个不同的命令。在此示例中,这不是必需的,但想象一下“cat /usr/share/dict/words”是一个非常昂贵的操作,例如解压缩 50gb 文件。

cat /usr/share/dict/words | tee >(head -1 > h.txt) >(tail -1 > t.txt) > /dev/null

执行此命令后,我希望 h.txt 包含单词文件“A”的第一行,t.txt 包含文件“Zyzzogeton”的最后一行。

然而实际发生的情况是 h.txt 包含“A”,但 t.txt 包含“argillaceo”,大约占文件的 5%。

为什么会发生这种情况?看起来要么“尾部”进程提前终止,要么流正在混淆。

运行另一个类似的命令,如下所示,其行为符合预期:

cat /usr/share/dict/words | tee >(grep ^a > a.txt) >(grep ^z > z.txt) > /dev/null

在这个命令之后,我希望 a.txt 包含所有以“a”开头的单词,而 z.txt 包含所有以“z”开头的单词,这正是发生的情况。

那么为什么这不适用于“tail”,以及其他哪些命令这不起作用?


好吧,似乎发生的事情是一旦head -1命令完成后退出,这会导致tee为了获得 SIGPIPE,它尝试将进程替换设置写入命名管道,该管道生成一个EPIPE并根据man 2 write也会产生SIGPIPE在写作过程中,导致tee退出并迫使tail -1立即退出,并且cat左边有一个SIGPIPE以及。

如果我们在流程中添加更多内容,我们可以更好地看到这一点head并使输出更可预测并且也写入stderr不依赖于tee:

for i in {1..30}; do echo "$i"; echo "$i" >&2; sleep 1; done | tee >(head -1 > h.txt; echo "Head done") >(tail -1 > t.txt) >/dev/null

当我运行时它给了我输出:

1
Head done
2

所以在一切退出之前它只进行了 1 次循环迭代(尽管t.txt仍然只有1在里面)。如果我们那么做

echo "${PIPESTATUS[@]}"

we see

141 141

which 这个问题 https://stackoverflow.com/questions/19120263/why-exit-code-141-with-grep-qSIGPIPE以与我们在这里看到的非常相似的方式。

coreutils 维护者已将此作为示例添加到他们的tee“陷阱” http://www.pixelbeat.org/docs/coreutils-gotchas.html#tee为了未来的子孙后代。

要与开发人员讨论这如何符合 POSIX 合规性,您可以在以下位置查看(已关闭的 notabug)报告:http://debbugs.gnu.org/cgi/bugreport.cgi?bug=22195 http://debbugs.gnu.org/cgi/bugreport.cgi?bug=22195

如果您可以访问 GNU 版本 8.24,他们添加了一些可以提供帮助的选项(不在 POSIX 中),例如-p or --output-error=warn。如果没有它,您可以冒一点风险,但通过捕获和忽略 SIGPIPE 来获得问题中所需的功能:

trap '' PIPE
for i in {1..30}; do echo "$i"; echo "$i" >&2; sleep 1; done | tee >(head -1 > h.txt; echo "Head done") >(tail -1 > t.txt) >/dev/null
trap - PIPE

都会得到预期的结果h.txt and t.txt,但是如果发生了其他需要正确处理 SIGPIPE 的事情,那么您将无法使用这种方法。

另一个黑客选项是归零t.txt在开始之前不要让head进程列表完成直到其长度非零:

> t.txt; for i in {1..10}; do echo "$i"; echo "$i" >&2; sleep 1; done | tee >(head -1 > h.txt; echo "Head done"; while [ ! -s t.txt ]; do sleep 1; done) >(tail -1 > t.txt; date) >/dev/null
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

bash 进程替换和尾部结果不正确? 的相关文章

  • 从 csv 文件中删除特定列,保持输出上的相同结构[重复]

    这个问题在这里已经有答案了 我想删除第 3 列并在输出文件中保留相同的结构 输入文件 12 10 10 10 10 1 12 23 1 45 6 7 11 2 33 45 1 2 1 2 34 5 6 I tried awk F 3 fil
  • bash 中 :-(冒号破折号)的用法

    bash中这种风格的含义是什么 PUBLIC INTERFACE eth0 目的是什么 If PUBLIC INTERFACE存在且不为null 则返回其值 否则返回 eth0 实际上有一些记录在bash 手册页 http linux di
  • 如何在bash中使用jq从变量中包含的json中提取值

    我正在编写一个 bash 脚本 其中存储了一个 json 值 现在我想使用 Jq 提取该 json 中的值 使用的代码是 json val code lyz1To6ZTWClDHSiaeXyxg redirect to http examp
  • 匹配模式后添加行[重复]

    这个问题在这里已经有答案了 我有一个文件说test具有以下值 Linux Solaris Fedora Ubuntu AIX HPUX 如何在匹配 AIX 的行后面添加一行系统主机名 如果我做 echo hostname gt gt tes
  • Linux 中的动态环境变量?

    Linux 中是否可以通过某种方式拥有动态环境变量 我有一个网络服务器 网站遵循以下布局 site qa production 我想要一个环境变量 例如 APPLICATION ENV 当我在 qa 目录中时设置为 qa 当我在生产目录中时
  • 有没有办法让我简化这些回声? [复制]

    这个问题在这里已经有答案了 我仍在学习如何编写 shell 脚本 并且我面临着一个挑战 让我更容易回显 Name1 Name2 Name15 我不太确定从哪里开始 我已经想法 但如果我搞砸了 我不想看起来很傻 有什么帮助吗 我实际上还没有尝
  • jq:将对象数组转换为对象

    我收到了来自curl的回复 格式如下 list value 1 id 12 value 15 id 13 value 4 id 14 给定 id 之间的映射 如下所示 12 newId1 13 newId2 14 newId3 我想做这个
  • OSX bash 最小化窗口

    在 Mac 中并使用 bash shell 我想执行一个包含单个命令 启动 Jupyter Lab 的文件并立即最小化终端窗口 有没有办法在不安装第三方软件的情况下做到这一点 是的 只需使用osascript https ss64 com
  • 动态参数值取决于另一个动态参数值

    启动前提 非常严格的环境 Windows 7 SP1 Powershell 3 0 使用外部库的可能性有限或不可能 我正在尝试重写之前创建的 bash 工具 这次使用 PowerShell 在 bash 中 我实现了自动完成功能 以使该工具
  • 从 php 执行 bash 脚本并立即输出回网页

    我有一组 bash 和 Perl 脚本 开发在 Linux Box 上部署所需的目录结构 可选 从svn导出代码 从这个源构建一个包 这在终端上运行良好 现在 我的客户请求此流程的 Web 界面 例如 某些页面上的 创建新包 按钮将一一调用
  • 使用 sh 运行 bash 脚本

    我有 bash 脚本 它需要 bash 另一个人尝试运行它 sh script name sh 它失败了 因为 sh 是他的发行版中 dash 的符号链接 ls la bin sh lrwxrwxrwx 1 root root 4 Aug
  • 协助 awk/bash 捕获内存差异

    我正在尝试从以下文件中提取以下输出 xr lab show clock Thu Sep 19 14 38 02 812 WIB 14 38 02 893 WIB Thu Sep 19 2019 xr lab xr lab xr lab sh
  • 在bash脚本中分割字符串[重复]

    这个问题在这里已经有答案了 我想分割一个字符串并需要其中的一些参数 USER dn uid dfl3030 cn users cn accounts dc tenant dc ycs dc io cn Reb Lena Schmidt kr
  • bash中的用户名、密码程序

    我有一个程序 要求用户输入用户名和密码 然后将其存储在文本文件中 第一列是用户名 第二列是密码 我需要一个命令 在用户输入用户名和新密码时替换密码 如下我拥有的 bin bash admin menu Register User echo
  • 当 grep "\\" XXFile 我得到“尾随反斜杠”

    现在我想查找是否有包含 字符的行 我试过grep XXFile但它暗示 尾随反斜杠 但当我尝试时grep XXFile没关系 谁能解释一下为什么第一个案例无法运行 谢谢 区别在于 shell 处理反斜杠的方式 当你写的时候 在双引号中 sh
  • 通过 sed 使用 unix 变量将数据附加到每行末尾[重复]

    这个问题在这里已经有答案了 我有一个文件 我想使用 SED 将值附加到每行末尾的 unix 变量中 我已经通过 AWK 实现了这一点 但我想在 SED 中实现 像这样的东西 我已经尝试过以下命令 但它不起作用 sed i s BATCH R
  • 在两次之间每分钟执行一次 Cronjob

    我需要在 crontab 中每分钟运行一个 bash 脚本8 45am and 9 50am每天的 Code 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 8 home pull sh gt ho
  • 用于计算数据文件中数字列表的平均值的脚本

    文件data txt包含以下内容 1 00 1 23 54 4 213 2 3 4 脚本的输出应该是 ave 54 646 一些简单的脚本是首选 这是一种方法 awk s 1 END print ave s NR RS file ave 5
  • 在退出脚本之前等待后台进程完成

    在退出脚本 TCL Bash 之前 如何确保所有后台进程已完成执行 我正在考虑将所有后台进程 pid 写入 pid 文件 然后最后 pgrep pidfile 以查看在退出之前是否有任何进程仍在运行 有一些更简单的方法可以做到这一点吗 TC
  • 如何在多进程系统中实现锁定?

    我们正在并行运行许多詹金斯项目 我们使用 python 并且选择使用 pyenv 管理虚拟环境 不幸的是 pyenv 有一个众所周知的竞争条件 https github com yyuu pyenv issues 174 为了解决这个问题

随机推荐