如何在子shell中找出父shell的用户?

时间:2015-06-19 00:33:28

标签: linux bash shell

假设父shell的用户是foo。如果您运行类似sudo -u bar -i的内容,那么您将使用用户bar的子shell。那么,我怎样才能找到子shell中父shell的用户?也就是说,在上面的例子中,我怎么知道父shell的用户是foo

更新
我理解,通过一些黑客攻击,可以使用ps实现此目的。但是,如果一切可能的话,我会对一种不那么苛刻和更标准的方式更感兴趣。

更新2
在答案的帮助下,我最终采用了以下解决方案:

# 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

4 个答案:

答案 0 :(得分:2)

首先,bash有一个很好的内置变量$PPID,它保存其父进程的进程ID。

其次,/proc/<pid>/status | egrep '^Uid:' | awk '{ print $2 }'可用于获取正在运行进程的用户ID。

这意味着以下命令将撤消直接父进程的用户ID:

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

所以,在su的例子中,你需要上升两个级别,因为su本身已经在新用户下运行了。因此,以下命令可用于检索产生过程的用户ID:

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

请注意,$PPID在存储的bash脚本中使用时的行为可能会有所不同。

答案 1 :(得分:1)

您可以执行ps -ef并按照PPIDPID匹配的列表,直到找到您感兴趣的父进程。对于Linux,ps通常会给出第一列中进程的名称。

例如,我只输入ps -ef,并且(在我的命令之前忽略了大约一百行)得到这个(这很短,应该清楚):

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

并且使用sudo,vile仍然是父级,但是具有不同的进程链:

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也有-H--forest个选项,试图让结构更具可读性(但后者特别是通过缩进太多来打败它)。

例如,这是一个解析输出的脚本,并指出层次结构中发生登录shell的位置。 shell 名称没有标准,但登录shell通常显示为带领&#34; - &#34;在CMD列中:

#!/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;

并输出:

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  "

还使用OSX进行测试(第一列是数字):

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"

答案 2 :(得分:1)

您可以使用$PPID变量来帮助您完成一两个命令:

#!/bin/bash
USER=`ps u -p $PPID | awk '{print $1}'|tail -1`
echo $USER

答案 3 :(得分:0)

如果您像我一样,那么您真正想要的是调用 sudo 的用户的名称。如果是这样,那么您需要按照 this question

的变量 $SUDO_USER