如何获得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:

  • -isomeUser创build一个login shell,这意味着以下内容:

    • someUser用户特定的shellconfiguration文件(如果已定义)将被加载
    • $HOME指向someUser的主目录,所以不需要-H (尽pipe你仍然可以指定它)
    • 模拟shell的工作目录是someUser的主目录。
  • -s创build一个非loginshell:

    • 没有加载shell configuration文件 (尽pipe交互式非login shell的初始化文件是;例如~/.bashrc
    • 除非您还指定-H ,否则模拟过程将在$HOME报告原始用户的主目录。
    • 模拟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用户的$SHELLvariables在OSX 10.9上包含/bin/sh ,而在Ubuntu 12.04上是/bin/bash

模拟进程是否涉及shell,其环境将设置以下variables,反映调用用户和命令: SUDO_COMMANDSUDO_USERSUDO_UID=SUDO_GID

看到man sudoman 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

所以你想要:

  1. 作为一个不同的用户执行一个bash脚本的一部分
  2. 切换到该用户的$ 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'"