测试我的程序是否从bash/ksh/csh命令行执行

Grz*_*orz 5 c linux

我想知道我的程序是从命令行执行,还是通过system()调用执行,还是从脚本执行.

我最初想过获取父id(getppid()),并查找/proc/#pppid目录检查文件的exe链接或内容cmdline.如果它是/ bin/bash,或/ bin/csh,或/ bin/sh,我会知道它是从命令行运行的.

问题是它不是真的,因为一个独立的脚本也会告诉我/bin/bash.即使它工作,它可能是非常具体的Linux版本方法,并可能在未来停止工作.

有没有更好的方法呢?

感谢您提出任何建议或指出某些方向.

Mar*_*ick 1

自 1980 年以来编写的大多数 shell 都支持作业控制,这是通过为命令管道中的每个进程分配进程组来实现的。进程组由setpgrp()设置,它将进程的 pgrp 设置为其 pid。

pgrp 是跨分支继承的。

因此,如果您的 shell 是一个相对现代的 shell,则由交互式 shell 启动的程序将具有getpid() == getpgrp(),并且该进程派生的任何其他进程(例如,如果它是 shell 脚本或调用system())将具有getpid() != getpgrp()

这是一个测试程序,及其在 bash 下的行为(它在 ksh93 和 tcsh 下的行为也相同):

pp.c

#include <unistd.h>
#include <stdio.h>

main()
{
    printf("pid=%d pgrp=%d\n", (int)getpid(), (int)getpgrp());
}
Run Code Online (Sandbox Code Playgroud)


$ ./pp
pid=3164 pgrp=3164
$ ./pp &
[1] 3165
$ pid=3165 pgrp=3165
Run Code Online (Sandbox Code Playgroud)

在管道中,最左边的命令是进程组领导者。(这没有记录,但 bash、ksh93 和 tcsh 都是这样做的)。

$ ls|./pp
pid=3179 pgrp=3178
$ ./pp|cat
pid=3180 pgrp=3180
Run Code Online (Sandbox Code Playgroud)

调用 with 的程序system()将与其父程序具有相同的 pgrp:

pps.c

#include <stdlib.h>

main()
{
    system("./pp");
}
Run Code Online (Sandbox Code Playgroud)


$ ./pps
pid=4610 pgrp=4608
Run Code Online (Sandbox Code Playgroud)

在shell脚本中,shell是进程组领导者,它调用的任何命令都会继承pgrp:

pp.sh

#!/bin/sh
./pp
Run Code Online (Sandbox Code Playgroud)


$ ./pp.sh
pid=4501 pgrp=4500
Run Code Online (Sandbox Code Playgroud)

但是如果shell脚本exec是一个程序,pid不会改变,并且执行的程序将是进程组的领导者,所以你可能不想这样做。

ppe.sh

#!/bin/sh
exec ./pp
Run Code Online (Sandbox Code Playgroud)


$ ./ppe.sh
pid=4504 pgrp=4504
Run Code Online (Sandbox Code Playgroud)

在不太可能发生的情况下,用户关闭作业控制,每个命令都将具有与 shell 相同的 pgrp:

$ set +m
$ ./pp
pid=4521 pgrp=2990
$ ./pp
pid=4522 pgrp=2990
Run Code Online (Sandbox Code Playgroud)