我需要以不同的用户身份执行bash脚本的一部分,并在该用户的$HOME目录中执行.但是,我不确定如何确定这个变量.切换到该用户并调用$HOME不提供正确的位置:
# running script as root, but switching to a different user...
su - $different_user
echo $HOME
# returns /root/ but should be /home/myuser
Run Code Online (Sandbox Code Playgroud)
似乎问题在于我尝试在脚本中切换用户的方式:
$different_user=deploy
# create user
useradd -m -s /bin/bash $different_user
echo "Current user: `whoami`"
# Current user: root
echo "Switching user to $different_user"
# Switching user to deploy
su - $different_user
echo "Current user: `whoami`"
# Current user: root
echo "Current user: `id`"
# Current user: uid=0(root) gid=0(root) groups=0(root)
sudo su $different_user
# Current user: root
# Current user: uid=0(root) gid=0(root) groups=0(root)
Run Code Online (Sandbox Code Playgroud)
在bash脚本中以不同用户切换用户和执行命令的正确方法是什么?
mkl*_*nt0 95
更新:根据这个问题的标题,人们似乎只是想找到一种方法来寻找不同用户的主目录,而无需冒充该用户.
在这种情况下,最简单的解决方案是使用波段扩展和感兴趣的用户名,并结合使用eval(这是必需的,因为用户名必须作为不带引号的文字给出,以便波形扩展能够工作):
eval echo "~$different_user" # prints $different_user's home dir.
Run Code Online (Sandbox Code Playgroud)
注意:关于使用申请的常见警告eval ; 在这种情况下,假设您控制其值$different_user并将其视为仅仅是用户名.
相比之下,此答案的其余部分涉及模仿用户并在该用户的主目录中执行操作.
注意:
sudoers文件授权)可以通过其模拟其他用户sudo.sudo- 更改其配置可使其行为不同 - 请参阅man sudoers.以另一个用户身份执行命令的基本形式是:
sudo -H -u someUser someExe [arg1 ...]
# Example:
sudo -H -u root env # print the root user's environment
Run Code Online (Sandbox Code Playgroud)
注意:
-H,则模拟进程(在指定用户的上下文中调用的进程)将报告原始用户的主目录$HOME. someExe碰巧是shell) - 调用 shell的扩展- 在传递给模拟进程之前 - 显然仍然会发生.(可选)您可以使用或通过(n模仿)shell运行模拟进程,前缀someExe为-i 或 -s - 不指定someExe ...创建交互式 shell:
-i创建一个登录 shell someUser,其中包含以下内容:
someUser的用户特定的壳轮廓,如果定义的话,是装载.$HOME指向someUser的主目录,所以没有必要-H(尽管你仍然可以指定它)someUser主目录. -s 创建一个非登录shell:
~/.bashrc)-H,否则模拟过程将报告原始用户的主目录$HOME. 使用shell意味着在命令行上传递的字符串参数可能受到模拟shell的shell扩展(参见下面的特定于平台的差异)(可能在调用shell初始扩展之后); 比较以下两个命令(使用单引号来防止调用 shell 过早扩展):
# Run root's shell profile, change to root's home dir.
sudo -u root -i eval 'echo $SHELL - $USER - $HOME - $PWD'
# Don't run root's shell profile, use current working dir.
# Note the required -H to define $HOME as root`s home dir.
sudo -u root -H -s eval 'echo $SHELL - $USER - $HOME - $PWD'
Run Code Online (Sandbox Code Playgroud)
调用的shell由"SHELL环境变量(如果已设置)或shell(在passwd(5)中指定")(根据man sudo)确定.请注意,-s这是在调用用户的环境是重要的,而与-i它是模拟的用户.
请注意,有关shell相关行为的平台差异(使用-i或-s):
sudoLinux上显然只接受可执行文件或内置名称作为/ 后面的第一个参数-s-i,而OSX允许传递整个shell命令行; 例如,OSX sudo -u root -s 'echo $SHELL - $USER - $HOME - $PWD'直接接受(不需要eval),而Linux则不接受(截至sudo 1.8.95p).
sudoLinux上的旧版本不会将shell扩展应用于传递给shell的参数 ; 例如,使用sudo 1.8.3p1(例如,Ubuntu 12.04),sudo -u root -H -s echo '$HOME'只需回显字符串文字"$ HOME",而不是在root用户的上下文中扩展变量引用.至少sudo 1.8.9p5(例如,Ubuntu 14.04),这已得到修复.因此,为了确保在Linux上进行扩展,即使使用旧sudo版本,也要将整个命令作为单个参数传递给eval; 例如:sudo -u root -H -s eval 'echo $HOME'.(虽然在OSX上没有必要,但这也适用于那里.)
该root用户的$SHELL变量包含/bin/sh在OSX 10.9,而这是/bin/bash在Ubuntu 12.04.
无论是冒充过程涉及壳与否,它的环境将有以下变量设置,反映调用用户和命令:SUDO_COMMAND,SUDO_USER,SUDO_UID=,SUDO_GID.
见man sudo和man sudoers更多的细微之处.
向@DavidW和@Andrew提供灵感的帽子.
Dav*_* W. 21
在BASH中,您可以$HOME通过在用户的登录ID前加上波形符号来查找用户的目录.例如:
$ echo ~bob
Run Code Online (Sandbox Code Playgroud)
这将回显用户bob的$HOME目录.
但是,您说您希望能够以特定用户身份执行脚本.为此,您需要设置sudo.此命令允许您以特定用户身份执行特定命令.例如,以foo用户身份执行bob:
$ sudo -i -ubob -sfoo
Run Code Online (Sandbox Code Playgroud)
这将启动一个新shell,并将-i使用用户的默认环境和shell模拟登录(这意味着foo命令将从bob's$ HOME`目录执行.)
Sudo设置有点复杂,你需要成为超级用户才能看到颤抖的文件(通常/etc/sudoers).但是,此文件通常有几个可以使用的示例.
在此文件中,您可以指定您指定的可以运行命令的命令,用户以及该用户在执行该命令之前是否必须输入其密码.这通常是默认设置(因为它证明了这是用户而不是在用户获取可口可乐时过来的人.)但是,当您运行shell脚本时,通常需要禁用此功能.
Tri*_*onX 18
为了寻找轻量级方法找到用户家庭目录的人的替代答案......
而不是乱搞su黑客,或打扰发起另一个bashshell 的开销只是为了找到$HOME环境变量...
有一个专门针对此的命令: getent
getent passwd someuser | cut -f6 -d:
getent可以做更多...只需看到手册页.在passwdnsswitch的数据库将返回用户在录入/etc/passwd格式.只需将它拆分在冒号上:即可解析出字段.
应该安装在大多数Linux系统(或使用任何系统GNU库Ç(RHEL: glibc-common,德布:libc-bin)
这个问题的标题是如何在bash脚本中获取不同用户的$HOME目录?这就是人们从谷歌来这里寻找答案的原因。
user=pi
user_home=$(bash -c "cd ~$(printf %q $USER) && pwd")
Run Code Online (Sandbox Code Playgroud)
注意:之所以安全,是因为 bash(甚至 4.4 之前的版本)有自己的printf功能,其中包括:
%q quote the argument in a way that can be reused as shell input
看:help printf
# "ls /" is not dangerous so you can try this on your machine
# But, it could just as easily be "sudo rm -rf /*"
$ user="root; ls /"
$ printf "%q" "$user"
root\;\ ls\ /
# This is what you get when you are PROTECTED from code injection
$ user_home=$(bash -c "cd ~$(printf "%q" "$user") && pwd"); echo $user_home
bash: line 0: cd: ~root; ls /: No such file or directory
# This is what you get when you ARE NOT PROTECTED from code injection
$ user_home=$(bash -c "cd ~$user && pwd"); echo $user_home
bin boot dev etc home lib lib64 media mnt ono opt proc root run sbin srv sys tmp usr var /root
$ user_home=$(eval "echo ~$user"); echo $user_home
/root bin boot dev etc home lib lib64 media mnt ono opt proc root run sbin srv sys tmp usr var
Run Code Online (Sandbox Code Playgroud)
如果你这样做是因为你正在运行某些东西,root那么你可以使用 sudo 的力量:
user=pi
user_home=$(sudo -u $user sh -c 'echo $HOME')
Run Code Online (Sandbox Code Playgroud)
如果没有,您可以从 获取/etc/passwd。已经有很多使用evaland的例子getent,所以我将给出另一种选择:
user=pi
user_home=$(awk -v u="$user" -v FS=':' '$1==u {print $6}' /etc/passwd)
Run Code Online (Sandbox Code Playgroud)
如果我有一个包含许多其他 awk oneliners 的 bash 脚本并且不使用cut. 虽然许多人喜欢“编码高尔夫”以使用最少的字符来完成任务,但我更喜欢“工具高尔夫”,因为使用更少的工具可以使您的脚本具有更小的“兼容性足迹”。此外,您的同事或未来的自己也不需要阅读手册页来理解它。