通过sudo或su运行脚本时,我想获得原始用户。无论发生多次sudo
还是su
相互内部运行,都应该发生sudo su -
。
Answers:
结果:
使用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>
普通sudo:
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>
须藤su-:
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 ]#
苏多苏-; su tom:
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$
who am i
与相同who smells bad
。此外,它仅在STDIN
与TTY关联时才起作用。因此,如果您运行echo "hello" | who am i
它,将根本无法工作。
echo "hello" | who am i
除非脚本在没有终端的环境中运行,否则您将无法正常运行。然后,您可能会看到由于who am i
无法读取的stdin出现某种问题而导致的错误不起作用,在这种情况下,您可能会who am i
出于绝望的目的而尝试将数据管道传输到绝望状态。tylerl只是指出他已经走了那条路,而且管道无法正常工作,因为stdin必须可读且与TTY相关联。
logname
,事实证明它可以工作,而在哪里who am i
却不行。
没有完美的答案。更改用户ID时,通常不会保留原始用户ID,因此信息会丢失。某些程序(例如logname
和who -m
实施hack),他们在其中检查查看连接到哪个终端stdin
,然后检查以查看哪个用户在该终端上登录。
该解决方案通常可以使用,但并非万无一失,当然也不应该认为它是安全的。例如,假设是否who
输出以下内容:
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
用来su
扎根,并运行您的程序。如果STDIN
未重定向,logname
则将输出类似的程序tom
。如果是这样重定向的(例如从文件):
logname < /some/file
no login name
由于输入不是终端,因此结果为“ ”。但是,更有趣的是,用户可能会冒充其他登录用户的事实。由于Joe在pts / 1上登录,Tom可以假装通过运行成为他
logname < /dev/pts1
现在,它说joe
即使tom是执行命令的人。换句话说,如果您在任何类型的安全角色中使用此机制,那么您就疯了。
这是ksh
我在HP-UX上编写的功能。我不知道它将如何Bash
在Linux中使用。这个想法是该sudo
进程以原始用户身份运行,而子进程是目标用户。通过循环回父流程,我们可以找到原始流程的用户。
#
# 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
}
我知道最初的问题来自很久以前,但是人们(例如我)仍然在问,这似乎是提出解决方案的好地方。
THIS_USER=`pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1 | sed 's/[()]//g'`
那是唯一对我有用的东西。
user1683793的findUser()函数已移植bash
并扩展,因此它也返回存储在NSS库中的用户名。
#!/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"
循环返回并提供用户列表
根据user1683793的回答
通过排除非TTY进程,我跳过root作为登录的发起者。我不确定在某些情况下这是否可能导致过多损失
#!/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
或者who am i
没有给我想要的答案,尤其不能在较长的列表su user1
,su user2
,su user3
,...
我知道最初的问题来自很久以前,但是人们(例如我)仍然在问,这似乎是提出解决方案的好地方。
多次调用ps的替代方法:执行一次pstree调用
pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1
输出(登录为偶数时): (evan)
pstree参数:
获取第一用户的变化(这是登录)与grep -o
和head
。
限制:该命令可能不包含任何大括号()
(通常不正常)
在运行systemd-logind
的系统上,systemd API提供了此信息。如果要从Shell脚本访问此信息,则需要使用以下内容:
$ loginctl session-status \
| (read session_id ignored; loginctl show-session -p User $session_id)
User=1000
的session-status
和show-ssession
命令loginctl
具有不同的行为而没有参数:session-status
使用当前会话,但show-ssession
使用管理器。但是,show-session
由于脚本可读取,因此使用脚本更可取。这就是为什么loginctl
需要两次调用的原因。
who | awk '{print $1}'