如何获得bash脚本中不同用户的$ HOME目录?
我需要执行一个bash脚本的一部分作为一个不同的用户,并在该用户的$HOME
目录。 但是,我不知道如何确定这个variables。 切换到该用户并调用$HOME
不提供正确的位置:
# running script as root, but switching to a different user... su - $different_user echo $HOME # returns /root/ but should be /home/myuser
更新:
看来,问题是我试图切换用户在我的脚本的方式:
$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)
在bash脚本中以不同的用户切换用户并执行命令的正确方法是什么?
更新 :基于这个问题的标题,人们似乎来到这里只是寻找一种方式来find一个不同的用户的主目录,而不需要模仿该用户 。
在这种情况下,最简单的解决scheme是使用用户名兴趣的代字符扩展,并结合使用eval
(这是必须的,因为用户名必须作为不加引号的字面量来使用 ,以便代字符扩展工作):
eval echo "~$different_user" # prints $different_user's home dir.
注意: 关于使用eval
的通常注意事项适用 ; 在这种情况下,假定您控制$different_user
的值并知道它仅仅是一个用户名。
相比之下,这个答案的其余部分涉及模拟用户并 在该用户的主目录中执行操作 。
注意:
- 默认情况下pipe理员和其他用户通过
sudoers
文件授权可以通过sudo
模拟其他用户。 - 以下是基于
sudo
的默认configuration – 更改其configuration可以使其行为有所不同 – 请参阅man sudoers
。
作为另一个用户执行命令的基本forms是:
sudo -H -u someUser someExe [arg1 ...] # Example: sudo -H -u root env # print the root user's environment
注意:
- 如果忽略指定
-H
,模拟进程(在指定用户的上下文中调用的进程)将在$HOME
报告原始用户的主目录。 - 模拟进程将具有与调用进程相同的工作目录。
- 模拟进程不会对作为parameter passing的string文本进行shell扩展 ,因为在模拟进程中不涉及shell(除非
someExe
恰好是一个shell) – 调用 shell进行扩展 – 在传递到模拟进程之前 – 显然可以发生。
或者,您可以通过(n模拟)shell来运行模拟进程, someExe
是使用-i
或 -s
前缀someExe
,但不指定someExe ...
创build交互式 shell:
-
-i
为someUser
创build一个login shell,这意味着以下内容:-
someUser
的用户特定的shellconfiguration文件(如果已定义)将被加载 。 -
$HOME
指向someUser
的主目录,所以不需要-H
(尽pipe你仍然可以指定它) - 模拟shell的工作目录是
someUser
的主目录。
-
-
-s
创build一个非loginshell:- 没有加载shell configuration文件 (尽pipe交互式非login shell的初始化文件是;例如
~/.bashrc
) - 除非您还指定
-H
,否则模拟过程将在$HOME
报告原始用户的主目录。 - 模拟shell将具有与调用进程相同的工作目录。
- 没有加载shell configuration文件 (尽pipe交互式非login shell的初始化文件是;例如
使用shell意味着在命令行上传递的string参数可能会受到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'
被调用的shell是由“SHELL环境variables,如果被设置的话,或者在passwd(5)中指定的shell”(根据man sudo
)来确定的。 请注意,使用-s
是调用用户的环境很重要,而使用-i
它是模拟用户的。
请注意, 与shell相关的行为(使用-i
或-s
)存在平台差异 :
-
Linux上的
sudo
显然只接受一个可执行文件或内置的名字作为-s
/-i
之后的第一个参数 ,而OSX允许传递整个shell命令行; 例如,OSX直接(不需要eval
)接受sudo -u root -s 'echo $SHELL - $USER - $HOME - $PWD'
,而Linux不支持(比如sudo 1.8.95p
)。 -
Linux上较早版本的
sudo
不会将shell扩展应用于传递给shell的参数 ; 例如sudo 1.8.3p1
(比如Ubuntu 12.04),sudo -u root -H -s echo '$HOME'
只是回应string文字“$ HOME”,而不是在根用户的上下文中展开variables引用。 至lesssudo 1.8.9p5
(例如Ubuntu 14.04)已经修复。 因此,为了确保在Linux上使用较早的sudo
版本进行扩展,请将整个命令作为一个parameter passing给eval
; 例如:sudo -u root -H -s eval 'echo $HOME'
。 (虽然在OSX上不需要,但也可以在那里工作。) -
root
用户的$SHELL
variables在OSX 10.9上包含/bin/sh
,而在Ubuntu 12.04上是/bin/bash
。
模拟进程是否涉及shell,其环境将设置以下variables,反映调用用户和命令: SUDO_COMMAND
, SUDO_USER
, SUDO_UID=
, SUDO_GID
。
看到man sudo
和man sudoers
更多的微妙之处。
给@DavidW和@Andrew的帽子提示灵感。
在BASH中,您可以通过在用户的loginID前添加一个波浪字符来查找用户的$HOME
目录。 例如:
$ echo ~bob
这将回应用户bob
的$HOME
目录。
但是,你说你希望能够作为一个特定的用户执行脚本。 要做到这一点,你需要设置sudo 。 该命令允许您以特定用户的身份执行特定的命令。 例如,要以用户bob
身份执行foo
:
$ sudo -i -ubob -sfoo
这将启动一个新的shell, -i
将模拟用户的默认环境和shell的login(这意味着foo
命令将从bob's
$ HOME`目录执行)。
Sudo的设置有点复杂,你需要成为一个超级用户才能看到颤抖文件(通常是/etc/sudoers
)。 但是,这个文件通常有几个例子可以使用。
在此文件中,您可以指定可以运行命令的用户指定的命令,以及用户是否必须在执行该命令之前input密码。 这通常是默认的(因为它certificate这是用户,而不是在用户获得可口可乐时来的人)。但是,运行shell脚本时,通常要禁用此function。
为了一个替代的答案寻找一个轻量级的方式来find一个用户的家目录…
而不是乱搞su
hacks,或者打开另外一个bash
shell来寻找$HOME
环境variables的开销。
轻量级简单Homedir查询通过Bash
有一个特别的命令: getent
getent passwd someuser | cut -f6 -d:
getent
可以做更多…只要看手册页 。 passwd
nsswitch数据库将以/etc/passwd
格式返回用户的条目。 只要把它分解在冒号上即可parsing出字段。
它应该安装在大多数Linux系统上(或任何使用GNU Lib C的系统 (RHEL: glibc-common
,Deb: libc-bin
)
在这种情况下,你需要sudo
的-u
选项。 从man
页:
The -u (user) option causes sudo to run the specified command as a user other than root.
如果你不需要真正运行它,你可以用~<user>
移动到他们的主目录。 在中,要进入我的主目录,您可以使用cd ~chooban
。
所以你想要:
- 作为一个不同的用户执行一个bash脚本的一部分
- 切换到该用户的$ HOME目录
受这个答案的启发,这里是你的脚本的改编版本:
#!/usr/bin/env bash different_user=deploy useradd -m -s /bin/bash "$different_user" echo "Current user: $(whoami)" echo "Current directory: $(pwd)" echo echo "Switching user to $different_user" sudo -u "$different_user" -i /bin/bash - <<-'EOF' echo "Current user: $(id)" echo "Current directory: $(pwd)" EOF echo echo "Switched back to $(whoami)" different_user_home="$(eval echo ~"$different_user")" echo "$different_user home directory: $different_user_home"
当你运行它,你应该得到以下内容:
Current user: root Current directory: /root Switching user to deploy Current user: uid=1003(deploy) gid=1003(deploy) groups=1003(deploy) Current directory: /home/deploy Switched back to root deploy home directory: /home/deploy
我也在寻找这个,但不想模仿一个用户简单地获得一个path!
user_path=$(grep $username /etc/passwd|cut -f6 -d":");
现在在你的脚本中,你可以参考$user_path
在大多数情况下会是/home/username
假设:您之前已经将$username
设置$username
预期用户用户名的值。 资料来源: http : //www.unix.com/shell-programming-and-scripting/171782-cut-fields-etc-passwd-file-into-variables.html
这在Linux中有效。 不知道如何在其他* nixes行为。
getent passwd "${OTHER_USER}"|cut -d\: -f 6
快速和肮脏,并将其存储在一个variables:
USER=somebody USER_HOME="$(echo -n $(bash -c "cd ~${USER} && pwd"))"
我正在努力解决这个问题,因为我正在寻找一种方法来在OS X的bash脚本中执行此操作,因此/ etc / passwd不可行,而且我的脚本是以root身份执行的,因此,调用eval或bash -c危险,因为它们允许代码注入到指定用户名的variables中。
这是我发现的。 这很简单,不会把一个variables放在一个子shell中。 但是,它确实需要脚本以root身份运行,因为脚本会跳转到指定的用户帐户。
假设$ SOMEUSER包含一个有效的用户名:
echo "$(sudo -H -u "$SOMEUSER" -s -- "cd ~ && pwd")"
我希望这可以帮助别人!
如果用户不存在, getent
将返回一个错误。
这里有一个小的shell函数,它不会忽略getent
的退出代码:
get_home() { local result; result="$(getent passwd "$1")" || return echo $result | cut -d : -f 6 }
这是一个用法示例:
da_home="$(get_home missing_user)" || { echo 'User does NOT exist!'; exit 1 } # Now do something with $da_home echo "Home directory is: '$da_home'"