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

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

症状很简单。例如:

ls | grep a | grep b | grep c | grep d

抛出

-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

grep使用的 s 和管道的数量没关系。有时ls | grep a也会抛出错误。

据我所知,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

已添加 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 调试输出
    • 斯特拉斯

答案1

以下几项操作可帮助您解决问题,最坏情况下可帮助您找出问题所在。在某些情况下,您可能需要结合这些步骤(例如 strace 和“尝试清除环境”)。

限制

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

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

日志记录

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

type log
这应该会返回类似“log: not found”的内容。如果它返回的是函数定义,请使用命令将其清除unset log

调试陷阱

trap -p

查看是否有任何与 DEBUG 或日志记录相关的陷阱输出。如果有,并且/或者定义了日志函数,则需要找出它们定义的位置并(至少暂时)删除它们。

它们可以在 .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 陷阱相结合几乎肯定是我所指的 bug。不幸的是,即使我订阅了 RHEL,也无法查看该 bug。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 的更新。

简要更新:

为了稍微澄清一下错误和故障模式之间的联系 - 发生的情况是,与日志记录函数和 DEBUG 钩子关联的进程 ID 交互的调用是无序的 - 竞争条件 - 导致诸如 getppid 之类的调用引用刚刚关闭的进程,从而导致您看到的错误。

附言一下,这是一项激进的日志记录功能。系统管理员显然不相信信任圈。

相关内容