我试图使标题简洁,但想不出一种完全概括问题的方法。这就是我想要做的:在运行 perl 脚本时,我想知道除了“我自己”之外是否有任何其他进程连接到同一个 STDERR 流(在当前 tty 中或可能附加/重定向到同一个STDERR 文件),如果是这样,我的目标是能够区分我的STDERR 错误/警告/详细消息以及来自其他同时运行的程序的任何其他消息。当我检测到这种可能性时,我想将我的脚本名称添加到我打印到 STDERR 的所有消息中,以便用户知道消息来自哪个进程(或者至少哪些来自我编写的脚本)。目前,我不在乎我是如何做到这一点的,也不关心解决方案是否封装了所有可能性——现在让我们称之为概念证明,它为一个体面的默认行为捕获了合理数量的用例。我正试图通过系统调用来做到这一点。
我希望考虑两种情况:来自同级进程的消息在一系列管道命令中同时运行,来自其他子进程的消息由同一个父脚本串行运行。我不会尝试使用同一 STDERR 流上的句柄来处理后台进程的情况,但如果这些被捕获,那将是一个奖励。
我相信我对第一个场景有很好的处理:兄弟进程。我可以使用pgrep -P $ppid
. 兄弟进程的简单存在足以保证脚本名称附加到我的消息中,但我什至可以更进一步并使用 lsof 来确定他们的 stderr 是否与我一样进入相同的 STDERR 流 - 例如它们在后台运行,并且它们的 STDERR 转到相同的 TTY(由文件描述符“2”推断)。我什至可以使用 perl 的 -p 或 -t 函数检查我是否是一系列管道命令的一部分(尽管我不想在文件已使用 '<' 或>',所以单独使用 -p 或 -t 不起作用)。不管,
我还没有充分弄清楚的场景是由父脚本控制的串行运行进程。我的想法是尝试对我的父进程是交互式 shell 还是脚本做出合理的猜测。
我已经尝试阅读 lsof 以确定是否有办法做到这一点。我有点猜测来自交互式外壳/终端的任何错误都不会打印到与我的脚本相同的 STDERR 流,但显然它们会打印,所以我不能简单地查找是否有任何输出从我的 tty父母区分这两种情况。
我创建了一个用于在不同上下文中进行测试的单行代码:
perl -e '$ppid=getppid();print("lsof -p $ppid:\n",`lsof -p $ppid`)'
我在 2 个上下文中运行它:一个直接在命令行上,另一个在 shell 脚本中。我在父 PID 上运行的 lsof 中看到的唯一区别是,当在命令行上运行时,有 5 个到 tty 的读/写连接,当从 shell 脚本中运行时,有 3 个到 tty 的连接和对 shell 脚本的一次只读读取。在任何情况下,文件描述符都不是 0、1 或 2。
交互式外壳:
...
tcsh 87854 me 15u CHR 16,2 0t3625 13083 /dev/ttys002
tcsh 87854 me 16u CHR 16,2 0t3625 13083 /dev/ttys002
tcsh 87854 me 17u CHR 16,2 0t3625 13083 /dev/ttys002
tcsh 87854 me 18u CHR 16,2 0t3625 13083 /dev/ttys002
tcsh 87854 me 19u CHR 16,2 0t3625 13083 /dev/ttys002
内壳脚本:
tcsh 89384 me 16r REG 1,3 363 19758500 /whatever/tmpdelete2.tcsh
tcsh 89384 me 17u CHR 16,2 0t4721 13083 /dev/ttys002
tcsh 89384 me 18u CHR 16,2 0t4721 13083 /dev/ttys002
tcsh 89384 me 19u CHR 16,2 0t4721 13083 /dev/ttys002
所以我的问题是:这里是否有足够的信息来合理地推断父进程是否是交互式 shell?
我可以从父进程的 REGular 只读文件中合理地推断出父进程不是交互式终端会话吗?或者我可以从 tty 的 5 个读/写连接中推断出父级是交互式外壳吗?
为了稍微测试这个想法,我尝试在sleep 1
我的单行代码上方的行上放置一个,以查看在长时间脚本执行期间的某个时间点,脚本的读取是否会脱离 lsof 输出。当我运行它时,我还尝试从 shell 脚本中重定向进出。
在我的用例中,我可以分辨出区别,但我不确定其他 shell 的行为方式。我真的只关心shell脚本。我想不出任何合理的场景,有人从其他任何东西中调用 perl 脚本......