简体   繁体   中英

Testing if my program is executed from the bash/ksh/csh command line

I would like to know if my program is executed from a command line, or executed through system() call, or from a script.

I initially thought about getting parent id ( getppid() ), and looking up /proc/#pppid directory checking either the exe link or contents of the cmdline file. If it is /bin/bash, or /bin/csh, or /bin/sh I would know that it runs from the command line.

The problem is that it is not true , because a standalone script would also tell me /bin/bash . Even if it worked, it could have been very specific Linux version approach and could stop working in a future.

Is there a better way to do that?

Thank you for any advice or pointing out to some direction.

Most shells written since 1980 support job control, which is implemented by assigning a process group to each process in a pipeline of commands. The process group is set by setpgrp() , which sets the process's pgrp to its pid.

The pgrp is inherited across forks.

So, if your shell is a relatively modern one, a program started by an interactive shell will have getpid() == getpgrp() , and any additional processes forked by that process (say, if it's a shell script or if it calls system() ) will have getpid() != getpgrp() .

Here's a test program, and its behavior under bash (it will behave the same under ksh93 and tcsh as well):

pp.c

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

main()
{
    printf("pid=%d pgrp=%d\n", (int)getpid(), (int)getpgrp());
}


$ ./pp
pid=3164 pgrp=3164
$ ./pp &
[1] 3165
$ pid=3165 pgrp=3165

In a pipeline, the leftmost command is the process group leader. (This isn't documented, but bash, ksh93, and tcsh all do it this way).

$ ls|./pp
pid=3179 pgrp=3178
$ ./pp|cat
pid=3180 pgrp=3180

A program called with system() will have the same pgrp as its parent:

pps.c

#include <stdlib.h>

main()
{
    system("./pp");
}


$ ./pps
pid=4610 pgrp=4608

In a shell script, the shell is the process group leader, and any command invoked by it will inherit the pgrp:

pp.sh

#!/bin/sh
./pp


$ ./pp.sh
pid=4501 pgrp=4500

But if the shell script exec sa program, the pid doesn't change, and the execed program will be a process group leader, so you probably don't want to do that.

ppe.sh

#!/bin/sh
exec ./pp


$ ./ppe.sh
pid=4504 pgrp=4504

In the unlikely case that the user turns off job control, every command is going to have the same pgrp as the shell:

$ set +m
$ ./pp
pid=4521 pgrp=2990
$ ./pp
pid=4522 pgrp=2990

您可以在脚本完成时拦截来自PID的信号并检查“kill”。

Not sure if that solves your problem but environment variables can give you a good hint. For example:

 $ set | grep "^_="
 _=
 $ bash -c "set" | grep "^_="
 _=/bin/bash
 $ sh -c "set" | grep "^_="
 _='/bin/sh'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM