我需要以不同的用户身份执行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脚本中以不同用户身份切换用户和执行命令的正确方法是什么?
答案 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
。 someExe
碰巧是shell) - 由扩展调用 shell - 在传递到模拟过程之前 - 显然仍然可以发生。或者,您可以通过someExe
前缀-i
或作为或通过(n模仿)shell 运行> -s
- 未指定someExe ...
创建交互式 shell:
-i
为someUser
创建登录 shell,其含义如下:
someUser
用户特定的shell配置文件(如果已定义)已加载。$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'
调用什么shell 由" SHELL环境变量(如果已设置)或shell(如passwd(5)"中指定)确定(根据man sudo
)。请注意,使用-s
时,调用用户的环境很重要,而使用-i
则模仿用户'第
请注意,有关与shell相关的行为的平台差异(使用-i
或-s
):
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
。
模拟过程是否涉及shell,其环境将设置以下变量,反映调用用户和命令:/bin/bash
,SUDO_COMMAND
,SUDO_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而烦恼...
专门针对此命令: 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)
所以你想:
受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
获取。已经有很多使用eval
和getent
的示例,因此我将给出另一个选择:
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