通过 sudo 或 su 运行脚本时,我想获取原始用户。这应该发生,无论多个sudo
或su
在彼此内部运行,特别是sudo su -
。
10 回答
结果:
使用who am i | awk '{print $1}'
OR logname
,因为不保证其他方法。
以自己的身份登录:
evan> echo $USER
evan
evan> echo $SUDO_USER
evan> echo $LOGNAME
evan
evan> whoami
evan
evan> who am i | awk '{print $1}'
evan
evan> logname
evan
evan>
普通须藤:
evan> sudo -s
root> echo $USER
root
root> echo $SUDO_USER
evan
root> echo $LOGNAME
root
root> whoami
root
root> who am i | awk '{print $1}'
evan
root> logname
evan
root>
须藤苏 - :
evan> sudo su -
[root ]# echo $USER
root
[root ]# echo $SUDO_USER
[root ]# echo $LOGNAME
root
[root ]# whoami
root
[root ]# who am i | awk '{print $1}'
evan
[root ]# logname
evan
[root ]#
须藤苏-; 苏汤姆:
evan> sudo su -
[root ]# su tom
tom$ echo $USER
tom
tom$ echo $SUDO_USER
tom$ echo $LOGNAME
tom
tom$ whoami
tom
tom$ who am i | awk '{print $1}'
evan
tom$ logname
evan
tom$
There's no perfect answer. When you change user IDs, the original user ID is not usually preserved, so the information is lost. Some programs, such as logname
and who -m
implement a hack where they check to see which terminal is connected to stdin
, and then check to see what user is logged in on that terminal.
This solution often works, but isn't foolproof, and certainly shouldn't be considered secure. For example, imagine if who
outputs the following:
tom pts/0 2011-07-03 19:18 (1.2.3.4)
joe pts/1 2011-07-03 19:10 (5.6.7.8)
tom
used su
to get to root, and runs your program. If STDIN
is not redirected, then a program like logname
will output tom
. If it IS redirected (e.g. from a file) as so:
logname < /some/file
Then the result is "no login name
", since the input isn't the terminal. More interestingly still, though, is the fact that the user could pose as a different logged in user. Since Joe is logged in on pts/1, Tom could pretend to be him by running
logname < /dev/pts1
Now, it says joe
even though tom is the one who ran the command. In other words, if you use this mechanism in any sort of security role, you're crazy.
This is a ksh
function I wrote on HP-UX. I don't know how it will work with Bash
in Linux. The idea is that the sudo
process is running as the original user and the child processes are the target user. By cycling back through parent processes, we can find the user of the original process.
#
# The options of ps require UNIX_STD=2003. I am setting it
# in a subshell to avoid having it pollute the parent's namespace.
#
function findUser
{
thisPID=$$
origUser=$(whoami)
thisUser=$origUser
while [ "$thisUser" = "$origUser" ]
do
( export UNIX_STD=2003; ps -p$thisPID -ouser,ppid,pid,comm ) | grep $thisPID | read thisUser myPPid myPid myComm
thisPID=$myPPid
done
if [ "$thisUser" = "root" ]
then
thisUser=$origUser
fi
if [ "$#" -gt "0" ]
then
echo $origUser--$thisUser--$myComm
else
echo $thisUser
fi
return 0
}
I know the original question was from a long time ago but people (such as me) are still asking and this looked like a good place to put the solution.
使用 logname(1) 获取用户的登录名怎么样?
ORIGIONAL_USER=$(pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1 | sed 's/[()]//g') && echo ${ORIGIONAL_USER}
That's the only thing that worked for me.
pstree
shows running processes as a tree. The tree is rooted at a pid, here given as $$
, which in bash expands to the process id of the current shell. So the first part of the command lists all the ancestor processes of the current shell with some funny formatting. The rest of the command discards the funny formatting to pick out the name of the user that owns the oldest ancestor process.
The main improvement over the other pstree
-based answer here is that extraneous parentheses are not included in the output.
user1683793's findUser() function ported to bash
and extended so it returns usernames stored in NSS libraries as well.
#!/bin/bash
function findUser() {
thisPID=$$
origUser=$(whoami)
thisUser=$origUser
while [ "$thisUser" = "$origUser" ]
do
ARR=($(ps h -p$thisPID -ouser,ppid;))
thisUser="${ARR[0]}"
myPPid="${ARR[1]}"
thisPID=$myPPid
done
getent passwd "$thisUser" | cut -d: -f1
}
user=$(findUser)
echo "logged in: $user"
cycling back and giving a list of users
based on user1683793's answer
By exlcuding non-TTY processes, I skip root as the initiator of the login. I'm not sure if that may exlcude too much in some case
#!/bin/ksh
function findUserList
{
typeset userList prevUser thisPID thisUser myPPid myPid myTTY myComm
thisPID=$$ # starting with this process-ID
while [ "$thisPID" != 1 ] # and cycling back to the origin
do
( ps -p$thisPID -ouser,ppid,pid,tty,comm ) | grep $thisPID | read thisUser myPPid myPid myTTY myComm
thisPID=$myPPid
[[ $myComm =~ ^su ]] && continue # su is always run by root -> skip it
[[ $myTTY == '?' ]] && continue # skip what is running somewhere in the background (without a terminal)
if [[ $prevUser != $thisUser ]]; then # we only want the change of user
prevUser="$thisUser" # keep the user for comparing
userList="${userList:+$userList }$thisUser" # and add the new user to the list
fi
#print "$thisPID=$thisUser: $userList -> $thisUser -> $myComm " >&2
done
print "$userList"
return 0
}
logname
or who am i
didn't give me the desired answer, especially not in longer lists of su user1
, su user2
, su user3
, ...
I know the original question was from a long time ago but people (such as me) are still asking and this looked like a good place to put the solution.
Alternative to calling ps multiple times: do one pstree call
pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1
output (when logged in as even): (evan)
pstree arguments:
- -l: long lines (not shortening)
- -u: show when user changes as (userName)
- -s $$: show parents of this process
Get the first user change (which is login) with grep -o
and head
.
limitation:the command may not contain any braces ()
(it does not normally)
On systems running systemd-logind
, the systemd API provides this information. If you want to access this information from a shell script, need to use something like this:
$ loginctl session-status \
| (read session_id ignored; loginctl show-session -p User $session_id)
User=1000
The session-status
and show-ssession
system commands of loginctl
have different behavior without arguments: session-status
uses the current session, but show-ssession
uses the manager. However, using show-session
is preferable for script use due to its machine-readable output. This is why two invocations of loginctl
are needed.
You can get it from the owner of the controlling terminal. Here's an old C code for a "whowasi" utility: http://sivann.gr/software/whowasi.c