How to find out the user of parent shell inside a

2019-02-26 04:45发布

Suppose the user of parent shell is foo. If you run something like sudo -u bar -i, then you are in a child shell with user bar. So, how can I find out the user of the parent shell inside the child shell? Namely, in the case above, how can I know that the user of parent shell is foo?

update
I understand that, with some hack, it is possible to achieve this using ps. However, I would be much more interested in a less hacky and more standard way, if all possible.

update 2
With help from the answers, I finally resorted to the following solution:

# from parent shell, user is foo
$ sudo -u bar -i PARENT=foo

# from child shell, show parent user foo
$ ps u -p $PPID | grep PARENT | cut -d= -f2

标签: linux bash shell
3条回答
爷、活的狠高调
2楼-- · 2019-02-26 04:54

You can use the $PPID variable to assist you along with a command or two:

#!/bin/bash
USER=`ps u -p $PPID | awk '{print $1}'|tail -1`
echo $USER
查看更多
【Aperson】
3楼-- · 2019-02-26 04:58

You can do a ps -ef and follow the list of PPID to PID matches until you find the parent process you are interested in. For Linux, ps usually gives the name of the process in the first column.

For instance, I just typed ps -ef, and (ignoring the hundred or so lines before my command) get this (which is short enough that it should be clear):

UID        PID  PPID  C STIME TTY          TIME CMD
tom       2925  2887  0 19:30 pts/0    00:00:00 screen
tom       2926  2925  0 19:30 ?        00:00:02 SCREEN
tom       2981  2926  0 19:30 pts/3    00:00:00 -bin/tcsh
tom       3005  2981  0 19:30 pts/3    00:00:00 ded
tom      11877  2926  0 19:56 pts/4    00:00:00 -bin/tcsh
tom      12103 11877  0 20:28 pts/4    00:00:01 vile
tom      12254 12103  0 20:54 pts/4    00:00:00 sh -c ps -ef
tom      12255 12254  0 20:54 pts/4    00:00:00 ps -ef

and with a sudo, vile is still the parent, but of a different chain of processes:

tom      12103 11877  0 20:28 pts/4    00:00:01 vile
tom      12302 12103  0 20:59 pts/4    00:00:00 sh -c sudo ps -ef
root     12303 12302  0 20:59 pts/4    00:00:00 sudo ps -ef
root     12306 12303  0 20:59 pts/4    00:00:00 ps -ef

Linux ps also has -H and --forest options which try to make the structure more readable (but the latter in particular defeats that by indenting too much).

For example, here is a script which parses the output, and points out the places where a login shell occurs in the hierarchy. There is no standard for shell names, but login shells commonly are shown with a leading "-" in the CMD column:

#!/usr/bin/perl -w

use strict;
use POSIX qw(getpid);

sub field($$$) {
    my $text  = shift;
    my $first = shift;
    my $last  = shift;
    $text = substr $text, $first, ($last - $first);
    $text =~ s/^\s+//;
    return $text;
}

our %processes;

# Get the current process-id
our $pid = getpid();
# Get the user for the current process
# Get a list of all processes, to reduce

if ( open ( my $fh, "ps -ef|" ) ) {
    my @data = <$fh>;
    close $fh;
    if ( $#data > 0 ) {
        my $head = $data[0];
        # formats differ, but this is an example which "works"
        my $c_uid  = (index $head, "UID") + 3;
        my $c_pid  = (index $head, "PID") + 3;
        my $c_ppid = (index $head, "PPID") + 4;
        my $c_cmd  = (index $head, "CMD");
        for my $n ( 1 .. $#data ) {
            chomp $data[$n];
            my $n_uid  = &field($data[$n], 0, $c_uid);
            my $n_pid  = &field($data[$n], $c_uid, $c_pid);
            my $n_ppid = &field($data[$n], $c_pid, $c_ppid);
            my $n_cmd  = &field($data[$n], $c_cmd, length($data[$n]));
            $n_uid = getpwuid($n_uid) if ( $n_uid =~ /^\d+$/ );
            my %obj;
            $obj{NAME} = $n_uid;
            $obj{CMD}  = $n_cmd;
            $obj{PPID} = $n_ppid;
            $processes{$n_pid} = \%obj;
        }
        while ( $processes{$pid} ) {
            my %obj = %{ $processes{$pid} };
            printf "pid %d %s \"%s\"\n", $pid, $obj{NAME}, $obj{CMD};
            printf "** login %s\n", $obj{NAME} if ( $obj{CMD} =~ /^-/ );
            $pid = $obj{PPID};
        }
    }
}

1;

and output:

pid 2724 tom "/usr/bin/perl -w ./my-parent"
pid 2723 tom "sh -c ./my-parent"
pid 2717 tom "ded /tmp"
pid 2686 tom "-tcsh"
** login tom
pid 2685 tom "sshd: tom@pts/0  "

also tested with OSX (where the first column is a number):

pid 3287 tom "/usr/bin/perl -w ./my-parent"
pid 2187 tom "vile /private/tmp/my-parent"
pid 1905 tom "ded /tmp"
pid 1876 tom "-tcsh"
** login tom
pid 1868 root "su - tom"
pid 1574 thomas "ded"
pid 1569 thomas "-bash"
** login thomas
pid 1563 root "login -pf thomas"
pid 1561 thomas "/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal"
pid 468 thomas "/sbin/launchd"
pid 1 root "/sbin/launchd"
查看更多
兄弟一词,经得起流年.
4楼-- · 2019-02-26 05:00

First of all, bash has a nice builtin variable called $PPID, which holds the process ID of its parent process.

Secondly, /proc/<pid>/status | egrep '^Uid:' | awk '{ print $2 }' can be used to obtain the user ID a process is running under.

This means the following command will retieve the user ID of the direct parent process:

cat /proc/$PPID/status | egrep '^Uid:' | awk '{ print $2 }'

So, in the example of su, you need to go up two levels since su itself will already run under the new user. Hence the following command can be used to retrieve the user ID of the spawning process:

cat /proc/$(cat /proc/$PPID/stat | awk '{ print $4 }')/status | egrep '^Uid:' | awk '{ print $2 }'

Note that $PPID may behave differently when used from within a stored bash-script.

查看更多
登录 后发表回答