如何在bash脚本中获取不同用户的$ HOME目录?

时间:2013-12-10 20:35:30

标签: bash

我需要以不同的用户身份执行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

更新

问题似乎与我尝试在脚本中切换用户的方式有关:

$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脚本中以不同用户身份切换用户和执行命令的正确方法是什么?

12 个答案:

答案 0 :(得分:88)

更新:根据这个问题的标题,人们似乎来到只是想找到找到其他用户的方式' s主目录,无需模仿该用户

在这种情况下,最简单的解决方案是将 tilde expansion与感兴趣的用户名结合使用eval (这是必需的,因为用户名必须是未加引号的文字以使代字号扩展能够正常工作):

eval echo "~$different_user"    # prints $different_user's home dir.

注意:通常caveats regarding the use of 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

注意:

  • 如果您忽略指定-H,模拟过程(在指定用户的上下文中调用的过程)将报告原始用户的主目录在$HOME
  • 模拟进程与调用进程具有相同的工作目录。
  • 模拟过程对作为参数传递的字符串文字执行无shell扩展,因为模拟过程中不涉及shell(除非someExe碰巧是shell) - 由扩展调用 shell - 在传递到模拟过程之前 - 显然仍然可以发生。

或者,您可以通过someExe前缀-i 或作为或通过(n模仿)shell 运行> -s - 未指定someExe ...创建交互式 shell:

  • -isomeUser创建登录 shell,其含义如下:

    • someUser 用户特定的shell配置文件(如果已定义)已加载
    • $HOME指向someUser的主目录,因此不需要-H (尽管您仍可以指定它)
    • 模拟shell的工作目录是someUser的主目录。
  • -s创建一个非登录shell:

    • 没有加载shell 配置文件(虽然交互式非登录 shell的初始化文件是;例如,~/.bashrc
    • 除非您还指定-H,否则模拟过程将在$HOME中报告原始用户的主目录。
    • 模拟shell将与调用进程具有相同的工作目录。

使用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'

调用什么shell 由" SHELL环境变量(如果已设置)或shell(如passwd(5)"中指定)确定(根据man sudo)。请注意,使用-s时,调用用户的环境很重要,而使用-i模仿用户'第

请注意,有关与shell相关的行为的平台差异(使用-i-s

    Linux上的
  • sudo显然只接受可执行文件或内置名称作为-s / {后面的第一个参数{1}} ,而OSX允许传递整个shell命令行;例如,OSX直接接受-i(不需要sudo -u root -s 'echo $SHELL - $USER - $HOME - $PWD'),而Linux则不接受eval

  • Linux上较早版本的sudo 1.8.95p不会将shell扩展应用于传递给shell的参数;例如,使用sudo(例如,Ubuntu 12.04),sudo 1.8.3p1只是回显字符串文字" $ HOME"而不是在root用户的上下文中扩展变量引用。截至至少sudo -u root -H -s echo '$HOME'(例如,Ubuntu 14.04),这已得到修复。因此,要确保在Linux上进行扩展(即使使用较早的sudo 1.8.9p5版本),请将整个命令作为单个参数传递给sudo;例如:eval。 (虽然在OSX上没有必要,但这也适用于那里。)

  • sudo -u root -H -s eval 'echo $HOME'用户的root变量在OSX 10.9上包含$SHELL,而在Ubuntu 12.04上则为/bin/sh

    < / LI>

模拟过程是否涉及shell,其环境将设置以下变量,反映调用用户和命令:/bin/bashSUDO_COMMANDSUDO_USER,{{1 }}

有关更多细微之处,请参阅SUDO_UID=SUDO_GID

给@DavidW和@Andrew提供灵感的帽子。

答案 1 :(得分:21)

在BASH中,您可以通过在用户的登录ID前加上波形符号来查找用户的$HOME目录。例如:

$ echo ~bob

这将回显用户bob的{​​{1}}目录。

但是,您说您希望能够以特定用户身份执行脚本。为此,您需要设置sudo。此命令允许您以特定用户身份执行特定命令。例如,以用户$HOME执行foo

bob

这将启动一个新shell,$ sudo -i -ubob -sfoo 将使用用户的默认环境和shell模拟登录(这意味着-i命令将从foo $ HOME执行`目录。)

Sudo设置有点复杂,你需要成为超级用户才能看到颤抖文件(通常为bob's)。但是,此文件通常有几个可以使用的示例。

在此文件中,您可以指定您指定的可以运行命令的命令,哪个用户以及该用户在执行该命令之前是否必须输入其密码。这通常是默认设置(因为它证明了这是用户而不是在用户获得可口可乐时过来的人。)但是,当您运行shell脚本时,通常需要禁用此功能。

答案 2 :(得分:16)

为那些寻找轻量级方式找到用户主页的人提供替代答案...

而不是弄乱su黑客攻击,或者为了找到bash环境变量来启动另一个$HOME shell而烦恼...

通过Bash轻量级简单Homedir查询

专门针对此命令: getent

getent passwd someuser | cut -f6 -d:

getent可以做更多事情......只需看man page即可。 passwd nsswitch数据库将以/etc/passwd格式返回用户的条目。只需将其拆分为冒号:即可解析出字段。

应安装在大多数Linux系统(或使用GNU Lib C的任何系统上(RHEL:glibc-common,Deb:libc-bin

答案 3 :(得分:3)

在这种情况下,您需要-u的{​​{1}}选项。来自sudo页面:

man

如果您不需要实际运行它,可以使用The -u (user) option causes sudo to run the specified command as a user other than root. 移动到其主目录。在进入我的主目录时,您将使用~<user>

答案 4 :(得分:2)

所以你想:

  1. 以其他用户身份执行 bash脚本的一部分
  2. 更改为该用户的$ HOME目录
  3. this answer的启发,这是您脚本的改编版本:

    #!/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
    

答案 5 :(得分:2)

这适用于Linux。不知道它在其他* nix中的表现如何。

  getent passwd "${OTHER_USER}"|cut -d\: -f 6

答案 6 :(得分:1)

我也在寻找这个,但不想模仿用户简单地获取路径!

user_path=$(grep $username /etc/passwd|cut -f6 -d":");

现在,在您的脚本中,您可以参考$user_path,大多数情况下会/home/username

假设:您之前已使用预期用户用户名的值设置$username。 资料来源:http://www.unix.com/shell-programming-and-scripting/171782-cut-fields-etc-passwd-file-into-variables.html

答案 7 :(得分:0)

快速而又脏,并将其存储在变量中:

USER=somebody
USER_HOME="$(echo -n $(bash -c "cd ~${USER} && pwd"))"

答案 8 :(得分:0)

我正在努力解决这个问题,因为我正在寻找一种方法在OS X的bash脚本中执行此操作,因此/ etc / passwd是不可能的,我的脚本应该以root身份执行,因此使解决方案调用eval或bash -c危险,因为它们允许代码注入指定用户名的变量。

这是我发现的。这很简单,并没有将变量放在子shell中。但是,它确实要求脚本在突然进入指定的用户帐户时由root运行。

假设$ SOMEUSER包含有效的用户名:

echo "$(sudo -H -u "$SOMEUSER" -s -- "cd ~ && pwd")"

我希望这有助于某人!

答案 9 :(得分:0)

如果用户不存在,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'"

答案 10 :(得分:0)

这个问题的标题是如何在bash脚本中获取不同用户的$ HOME目录?,这就是人们从Google来这里寻找答案的原因。

如果这样做是因为您正在以root的身份运行,则可以使用sudo的功能:

user=pi
user_home=$(sudo -u $user sh -c 'echo $HOME')

如果没有,您可以从/etc/passwd获取。已经有很多使用evalgetent的示例,因此我将给出另一个选择:

user=pi
user_home=$(awk -v FS=':' '$1=="'$u'"{print $6}' /etc/passwd)

如果我的bash脚本中有很多其他awk oneliners并且没有使用cut,那么我真的只会使用那个。尽管许多人喜欢“编码高尔夫”以使用最少的字符来完成任务,但我赞成“工具高尔夫”,因为使用较少的工具可使脚本的“兼容性足迹”更小。此外,您的同事或未来自我所需的手册页也更少了。

答案 11 :(得分:0)

library(RODBC) db <- "C:/Projects/stuff.accdb" desc<-read.csv("C:/Projects/description.csv",header=TRUE) col <- odbcConnectAccess2007(db) for (i in 330) { sqlquery(col,paste("update COL set groups=1 where description='SLIP-ONS, LT, GREEN'")) } close(col) 的输出可以使用Bash正则表达式进行解析

getent passwd username