bash 中的链式管道抛出“不允许操作”

Jeo*_*eon 5 bash centos-5

症状很简单。例如:

ls | grep a | grep b | grep c | grep d
Run Code Online (Sandbox Code Playgroud)

投掷

-bash: child setpgid (8948 to 8943): Operation not permitted
-bash: child setpgid (8950 to 8943): Operation not permitted
-bash: child setpgid (8952 to 8943): Operation not permitted
-bash: child setpgid (8953 to 8943): Operation not permitted
-bash: child setpgid (8954 to 8943): Operation not permitted
-bash: child setpgid (8955 to 8943): Operation not permitted
-bash: child setpgid (8962 to 8957): Operation not permitted
-bash: child setpgid (8964 to 8957): Operation not permitted
-bash: child setpgid (8966 to 8957): Operation not permitted
-bash: child setpgid (8967 to 8957): Operation not permitted
-bash: child setpgid (8968 to 8957): Operation not permitted
-bash: child setpgid (8969 to 8957): Operation not permitted
-bash: child setpgid (8976 to 8971): Operation not permitted
-bash: child setpgid (8978 to 8971): Operation not permitted
-bash: child setpgid (8980 to 8971): Operation not permitted
-bash: child setpgid (8981 to 8971): Operation not permitted
-bash: child setpgid (8982 to 8971): Operation not permitted
-bash: child setpgid (8983 to 8971): Operation not permitted
-bash: child setpgid (8990 to 8985): Operation not permitted
-bash: child setpgid (8992 to 8985): Operation not permitted
-bash: child setpgid (8994 to 8985): Operation not permitted
-bash: child setpgid (8995 to 8985): Operation not permitted
-bash: child setpgid (8996 to 8985): Operation not permitted
-bash: child setpgid (8997 to 8985): Operation not permitted
Run Code Online (Sandbox Code Playgroud)

grep使用的 s 和管道的数量并不重要。有时ls | grep a也会抛出错误。

AFAIK,lsanadgrep不需要 root 权限。因此,我想知道如何解决这个问题。

当前机器是Cent OS 5(内核2.6.18)。如果您需要更详细的信息,请告诉我。

添加:ls和的踪迹grep

type ls
ls is aliased to `ls -hF --color=auto'
which ls
/bin/ls
type grep
grep is /bin/grep
which grep
/bin/grep
Run Code Online (Sandbox Code Playgroud)

已添加 2

这时我发现这不仅仅限于ls和grep。似乎它适用于所有使用管道的命令。例如,echo 'Hello' | tee outfile抛出相同的错误。

添加 3:响应@Argonauts'

由于日志太长,请参考https://gist.github.com/anonymous/5459fa0322d178f85b0cd2d5ee2add53

简而言之,

  • ulimit -a
    • 管道大小(512 字节,-p)8
    • 最大用户进程数 (-u) 129094
  • type log-bash: type: log: not found好的
  • trap -ptrap -- 'history_to_syslog' DEBUG: 。会引起问题吗?
  • 在干净的环境下尝试:有时不报错,有时报错。
  • 需要调查
    • Bash 调试输出
    • 斯特雷斯

Arg*_*uts 3

这里有一些可以尝试的方法,最好的情况下应该有助于解决您的问题,最坏的情况下应该有助于找出问题“不”是什么。在某些情况下,您可能需要组合这些步骤(例如 strace 和“尝试清除环境”)。

极限值

使用以下命令检查您的 shell 中允许的进程数或管道最大大小是否设置了异常低的限制: ulimit -a

如果可以,请将该命令的输出附加到您的问题中。

记录

在旧版本的 bash 管道上,由于启用了日志记录功能(bash < 4.1),管道可能会中断。

type log
这应该返回类似“日志:未找到”的内容。如果它返回一个函数定义,请使用命令将其清除unset log

调试陷阱

trap -p

查看是否有任何陷阱输出链接到调试或日志记录。如果它们是和/或定义了日志函数,您需要找出它们的定义位置并(至少暂时)删除它们。

它们可以在 .bashrc、.bash_profile 和任何其他相关初始化文件中定义。由于它似乎也会影响 root,因此更有可能在/etc/bashrc 或 /etc/profile 等系统级文件中找到它。

至少您可以清除当前环境中的陷阱和日志功能,看看是否能解决问题。

在干净的环境下尝试

检查这一点的另一种方法是使用(固定)运行管道命令

env -i ls | env -i grep a | env -i grep b | env -i grep c | env -i grep d

清除环境(对于该命令序列)。您可能需要更改命令以包含完整路径。看看ulimit -a在这种环境下的值是否有所不同也是值得的。

Bash 调试输出

在运行管道 cmd 序列之前,在set -x命令行中键入,这将打开 bash 调试 - 所有“幕后”命令都将打印到屏幕上。您可能会看到一些奇怪的东西 - 调用另一个函数的钩子,类似于上面讨论的日志问题 - 或其他奇怪的东西。

斯特雷斯

使用 strace 运行命令:
strace ls | grep a | grep b | grep c | grep d

看看究竟发生了什么。如果您想发布这些结果,您可能需要将它们放在 Pastebin 或类似网站上并发布链接。这是解决该问题最有可能的方法,但输出可能难以解码。

更新

查看您的日志后:

  1. 当使用 env -i 时,管道的每个阶段都需要使用它 - 每个阶段实际上都是一个单独的 shell 实例。我的错。 env -i ls | env -i grep a | env -i grep b | env -i grep c | env -i grep d

  2. 每次调用之间调用的日志记录函数与 DEBUG 陷阱相结合几乎肯定是我所指的错误。不幸的是,即使我订阅了 RHEL,也无法查看该错误。它是https://bugzilla.redhat.com/show_bug.cgi?id=720464

当日志记录与调试陷阱一起发生时,此错误导致了竞争条件,这正是您所发生的情况 - set -x 清楚地显示了发出的每个命令的相当广泛的日志记录(到系统日志)。

因为管道会创建子 shell,所以您不能只在顶级 shell 中清除它并发出管道命令。下一个管道阶段将定义它。对上面第 1 项中的更改进行重新测试将表明,即使没有这些钩子,它也能正常工作。

错误报告表明修复程序没有向后移植。我在这里放置了 rhel 的一些详细信息:http ://pastebin.com/dymenY7e

您需要清除陷阱和/或删除日志记录函数history_to_syslog 的定义。如果您具有root 访问权限,则绝对可以永久删除它。我在原来的答案中给出了一些关于去哪里寻找的提示。

您可以尝试检查 Centos 5 的 bash 更新,但我上面链接的信息表明没有创建到 rhel 5 的反向端口,因此不太可能是 Centos 5 的更新。

简要更新:

为了稍微澄清一下 bug 和故障模式之间的关系 - 发生的情况是,与日志记录函数和 DEBUG 挂钩关联的进程 id 进行交互的调用不按顺序发生 - 竞争条件 - 导致引用进程的调用,例如 getppid刚刚关闭,导致您看到错误。

顺便说一句,这是一种积极的日志记录功能。系统管理员显然不相信信任圈。