bash 如何在bash脚本中获取不同用户的$HOME目录?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20504662/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get $HOME directory of different user in bash script?
提问by Andrew
I need to execute part of a bash script as a different user, and inside that user's $HOME
directory. However, I'm not sure how to determine this variable. Switching to that user and calling $HOME
does not provide the correct location:
我需要以不同的用户身份在该用户的$HOME
目录中执行部分 bash 脚本。但是,我不确定如何确定这个变量。切换到该用户并拨打电话$HOME
无法提供正确的位置:
# running script as root, but switching to a different user...
su - $different_user
echo $HOME
# returns /root/ but should be /home/myuser
Update:
更新:
It appears that the issue is with the way that I am trying to switch users in my script:
问题似乎出在我尝试在脚本中切换用户的方式上:
$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)
What is the correct way to switch users and execute commands as a different user in a bash script?
在 bash 脚本中切换用户并以不同用户身份执行命令的正确方法是什么?
回答by mklement0
Update: Based on this question's title, people seem to come here just looking for a way to finda different user's home directory, without the need to impersonatethat user.
更新:根据这个问题的标题,人们来到这里似乎只是想寻找一种方法来查找不同用户的主目录,而无需模拟该用户。
In that case, the simplest solution is to use tilde expansionwith the username of interest, combined with eval
(which is needed, because the username must be given as an unquoted literalin order for tilde expansion to work):
在这种情况下,最简单的解决方案是对感兴趣的用户名使用波浪号扩展,并结合eval
(这是必需的,因为用户名必须作为未加引号的文字给出,以便波浪号扩展工作):
eval echo "~$different_user" # prints $different_user's home dir.
Note: The usual caveats regarding the use of eval
apply; in this case, the assumption is that you control the value of $different_user
and know it to be a mere username.
注意:关于使用apply的通常警告eval
;在这种情况下,假设您控制 的值$different_user
并知道它只是一个用户名。
By contrast, the remainder of this answer deals with impersonatinga user andperforming operations in that user's home directory.
相比之下,此答案的其余部分涉及模拟用户并在该用户的主目录中执行操作。
Note:
笔记:
- Administrators by default and other users if authorized via the
sudoers
file can impersonate other users viasudo
. - The following is based on the defaultconfiguration of
sudo
- changing its configuration can make it behave differently - seeman sudoers
.
- 默认情况下,管理员和其他用户如果通过
sudoers
文件授权可以通过sudo
. - 以下是基于默认配置
sudo
- 更改其配置可以使其行为不同 - 请参阅man sudoers
。
The basic formof executing a command as another user is:
以其他用户身份执行命令的基本形式是:
sudo -H -u someUser someExe [arg1 ...]
# Example:
sudo -H -u root env # print the root user's environment
Note:
笔记:
- If you neglect to specify
-H
, the impersonating process (the process invoked in the context of the specified user) will report the originaluser's home directory in$HOME
. - The impersonating process will have the same working directory as the invoking process.
- The impersonating process performs no shell expansionson string literals passed as arguments, since no shell is involved in the impersonating process (unless
someExe
happens to be a shell) - expansions by the invokingshell - prior to passing to the impersonating process - can obviously still occur.
- 如果您忽略指定
-H
,则模拟进程(在指定用户的上下文中调用的进程)将在 中报告原始用户的主目录$HOME
。 - 模拟进程将具有与调用进程相同的工作目录。
- 模拟进程对作为参数传递的字符串文字不执行shell 扩展,因为模拟过程中不涉及 shell(除非
someExe
恰好是 shell)——调用shell 的扩展——在传递给模拟进程之前——显然仍然会发生.
Optionally, you can have an impersonating process run as or via a(n impersonating) shell, by prefixing someExe
either with -i
or-s
- not specifying someExe ...
creates an interactiveshell:
任选地,可以有一个冒充过程运行或作为通过第(n冒充)壳,由前缀someExe
与任一-i
或-s
-未指定someExe ...
创建交互式壳:
-i
creates a loginshell forsomeUser
, which implies the following:someUser
's user-specific shell profile, if defined, is loaded.$HOME
points tosomeUser
's home directory, so there's no need for-H
(though you may still specify it)- The working directory for the impersonating shell is the
someUser
's home directory.
-s
creates a non-login shell:- no shell profileis loaded (though initialization files for interactive nonloginshells are; e.g.,
~/.bashrc
) - Unless you also specify
-H
, the impersonating process will report the originaluser's home directory in$HOME
. - The impersonating shell will have the same working directory as the invoking process.
- no shell profileis loaded (though initialization files for interactive nonloginshells are; e.g.,
-i
为 创build一个登录shellsomeUser
,这意味着以下内容:someUser
的用户特定的 shell 配置文件(如果已定义)将被加载。$HOME
指向someUser
的主目录,因此不需要-H
(尽管您仍然可以指定它)- 模拟 shell 的工作目录是
someUser
的主目录。
-s
创建一个非登录shell:- 没有加载shell配置文件(尽管交互式非登录shell 的初始化文件是;例如,
~/.bashrc
) - 除非您还指定
-H
,否则模拟进程将在 中报告原始用户的主目录$HOME
。 - 模拟 shell 将具有与调用进程相同的工作目录。
- 没有加载shell配置文件(尽管交互式非登录shell 的初始化文件是;例如,
Using a shell means that string arguments passed on the command line MAY be subject to shell expansions- see platform-specific differences below- by the impersonating shell (possibly after initial expansion by the invoking shell); compare the the following two commands (which use singlequotes to prevent premature expansion by the invokingshell):
使用 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'
What shellis invoked is determined by "the SHELL environment variable if it is set or the shell as specified in passwd(5)" (according to man sudo
). Note that with -s
it is the invokinguser's environment that matters, whereas with -i
it is the impersonateduser's.
调用什么 shell由“设置的 SHELL 环境变量或 passwd(5) 中指定的 shell”决定(根据man sudo
)。请注意,-s
重要的是调用用户的环境,而-i
它是模拟用户的环境。
Note that there are platform differences regarding shell-related behavior (with -i
or -s
):
请注意,与 shell 相关的行为(使用-i
或-s
)存在平台差异:
sudo
on Linux apparently only accepts an executable or builtinname as the firstargument following-s
/-i
, whereas OSX allows passing an entire shell command line; e.g., OSX acceptssudo -u root -s 'echo $SHELL - $USER - $HOME - $PWD'
directly (no need foreval
), whereas Linux doesn't (as ofsudo 1.8.95p
).Older versions of
sudo
on Linux do NOT apply shell expansions to arguments passed to a shell; for instance, withsudo 1.8.3p1
(e.g., Ubuntu 12.04),sudo -u root -H -s echo '$HOME'
simply echoes the string literal "$HOME" instead of expanding the variable reference in the context of the root user. As of at leastsudo 1.8.9p5
(e.g., Ubuntu 14.04) this has been fixed. Therefore, to ensure expansion on Linux even with oldersudo
versions, pass the the entire command as a single argument toeval
; e.g.:sudo -u root -H -s eval 'echo $HOME'
. (Although not necessary on OSX, this will work there, too.)The
root
user's$SHELL
variable contains/bin/sh
on OSX 10.9, whereas it is/bin/bash
on Ubuntu 12.04.
sudo
在 Linux 上显然只接受一个可执行文件或内置名称作为/ 之后的第一个参数-s
-i
,而 OSX 允许传递整个 shell 命令行;例如,OSXsudo -u root -s 'echo $SHELL - $USER - $HOME - $PWD'
直接接受(不需要eval
),而 Linux 不接受(从 开始sudo 1.8.95p
)。sudo
Linux 上的旧版本不将 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。
Whether the impersonating process involves a shell or not, its environment will have the following variables set, reflecting the invoking user and command: SUDO_COMMAND
, SUDO_USER
, SUDO_UID=
, SUDO_GID
.
无论模拟进程是否涉及 shell,其环境都将设置以下变量,反映调用用户和命令:SUDO_COMMAND
、SUDO_USER
、SUDO_UID=
、SUDO_GID
。
See man sudo
and man sudoers
for many more subtleties.
查看man sudo
和man sudoers
了解更多细微之处。
Tip of the hat to @DavidW and @Andrew for inspiration.
向@DavidW 和@Andrew 致敬以寻求灵感。
回答by David W.
In BASH, you can find a user's $HOME
directory by prefixing the user's login ID with a tilde character. For example:
在 BASH 中,您可以$HOME
通过在用户的登录 ID 前面加上波浪号字符来查找用户的目录。例如:
$ echo ~bob
This will echo out user bob
's $HOME
directory.
这将呼出 userbob
的$HOME
目录。
However, you say you want to be able to execute a script as a particular user. To do that, you need to setup sudo. This command allows you to execute particular commands as either a particular user. For example, to execute foo
as user bob
:
但是,您说您希望能够以特定用户身份执行脚本。为此,您需要设置sudo。此命令允许您以特定用户身份执行特定命令。例如,以foo
用户身份执行bob
:
$ sudo -i -ubob -sfoo
This will start up a new shell, and the -i
will simulate a login with the user's default environment and shell (which means the foo
command will execute from the bob's
$HOME` directory.)
这将启动一个新的 shell,并且-i
将使用用户的默认环境和 shell 模拟登录(这意味着该foo
命令将从bob's
$HOME` 目录执行。)
Sudo is a bit complex to setup, and you need to be a superuser just to be able to see the shudders file (usually /etc/sudoers
). However, this file usually has several examples you can use.
Sudo 的设置有点复杂,您需要成为超级用户才能看到 shudders 文件(通常为/etc/sudoers
)。但是,该文件通常有几个您可以使用的示例。
In this file, you can specify the commands you specify who can run a command, as which user, and whether or not that user has to enter their password before executing that command. This is normally the default (because it proves that this is the user and not someone who came by while the user was getting a Coke.) However, when you run a shell script, you usually want to disable this feature.
在此文件中,您可以指定由谁可以运行命令、以哪个用户身份以及该用户在执行该命令之前是否必须输入其密码的命令。这通常是默认设置(因为它证明这是用户而不是在用户获取可乐时经过的人。)但是,当您运行 shell 脚本时,您通常希望禁用此功能。
回答by TrinitronX
For the sake of an alternative answer for those searching for a lightweight way to just find a user's home dir...
为了那些寻找轻量级方法来查找用户主目录的人的替代答案......
Rather than messing with su
hacks, or bothering with the overhead of launching another bash
shell just to find the $HOME
environment variable...
而不是搞乱su
黑客,或者打扰启动另一个bash
shell的开销只是为了找到$HOME
环境变量......
Lightweight Simple Homedir Query via Bash
通过 Bash 的轻量级简单 Homedir 查询
There is a command specifically for this: getent
有一个专门用于此的命令: getent
getent passwd someuser | cut -f6 -d:
getent passwd someuser | cut -f6 -d:
getent
can do a lot more... just see the man page. The passwd
nsswitch database will return the user's entry in /etc/passwd
format. Just split it on the colon :
to parse out the fields.
getent
可以做更多...只需查看手册页。在passwd
nsswitch的数据库将返回用户在录入/etc/passwd
格式。只需在冒号上将其拆分:
即可解析字段。
It should be installed on most Linux systems (or any system that uses GNU Lib C(RHEL: glibc-common
, Deb: libc-bin
)
它应该安装在大多数 Linux 系统(或任何使用GNU Lib C(RHEL: glibc-common
, Deb: libc-bin
)
回答by chooban
You want the -u
option for sudo
in this case. From the man
page:
在这种情况下,您需要该-u
选项sudo
。从man
页面:
The -u (user) option causes sudo to run the specified command as a user other than root.
If you don't need to actually run it as them, you could move to their home directory with ~<user>
. As in, to move into my home directory you would use cd ~chooban
.
如果您不需要像他们一样实际运行它,则可以使用~<user>
. 就像,要进入我的主目录,您将使用cd ~chooban
.
回答by Michael Kropat
So you want to:
所以你想:
- execute part of a bash scriptas a different user
- change to that user's $HOME directory
- 以不同的用户身份执行bash 脚本的一部分
- 切换到该用户的 $HOME 目录
Inspired by this answer, here's the adapted version of your script:
#!/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"
When you run it, you should get the following:
当你运行它时,你应该得到以下信息:
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
回答by hydrian
This works in Linux. Not sure how it behaves in other *nixes.
这适用于Linux。不确定它在其他 *nix 中的表现如何。
getent passwd "${OTHER_USER}"|cut -d\: -f 6
回答by Grizly
I was also looking for this, but didn't want to impersonate a user to simply acquire a path!
我也在寻找这个,但不想冒充用户来简单地获取路径!
user_path=$(grep $username /etc/passwd|cut -f6 -d":");
user_path=$(grep $username /etc/passwd|cut -f6 -d":");
Now in your script, you can refer to $user_path
in most cases would be /home/username
现在在您的脚本中,您可以$user_path
在大多数情况下参考/home/username
Assumes: You have previously set $username
with the value of the intended users username.
Source: http://www.unix.com/shell-programming-and-scripting/171782-cut-fields-etc-passwd-file-into-variables.html
假设:您之前已$username
使用预期用户用户名的值进行设置。来源:http: //www.unix.com/shell-programming-and-scripting/171782-cut-fields-etc-passwd-file-into-variables.html
回答by Quote
I was struggling with this question because I was looking for a way to do this in a bash script for OS X, hence /etc/passwd was out of the question, and my script was meant to be executed as root, therefore making the solutions invoking eval or bash -c dangerous as they allowed code injection into the variable specifying the username.
我一直在努力解决这个问题,因为我正在寻找一种在 OS X 的 bash 脚本中执行此操作的方法,因此 /etc/passwd 是不可能的,并且我的脚本旨在以 root 身份执行,因此制定了解决方案调用 eval 或 bash -c 是危险的,因为它们允许将代码注入到指定用户名的变量中。
Here is what I found. It's simple and doesn't put a variable inside a subshell. However it does require the script to be ran by root as it sudos into the specified user account.
这是我发现的。它很简单,不会在子外壳中放置变量。但是,它确实需要由 root 运行脚本,因为它 sudos 到指定的用户帐户。
Presuming that $SOMEUSER contains a valid username:
假设 $SOMEUSER 包含一个有效的用户名:
echo "$(sudo -H -u "$SOMEUSER" -s -- "cd ~ && pwd")"
I hope this helps somebody!
我希望这对某人有所帮助!
回答by Elifarley
If the user doesn't exist, getent
will return an error.
如果用户不存在,getent
将返回错误。
Here's a small shell function that doesn't ignore the exit code of getent
:
这是一个不忽略退出代码的小 shell 函数getent
:
get_home() {
local result; result="$(getent passwd "")" || return
echo $result | cut -d : -f 6
}
Here's a usage example:
这是一个使用示例:
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'"
回答by Bruno Bronosky
The title of this question is How to get $HOME directory of different user in bash script?and that is what people are coming here from Google to find out.
这个问题的标题是如何在 bash 脚本中获取不同用户的 $HOME 目录?这就是人们从谷歌来到这里寻找的。
If you are doing this because you are running something as root
then you can use the power of sudo:
如果您这样做是因为您正在运行某些东西,root
那么您可以使用 sudo 的功能:
user=pi
user_home=$(sudo -u $user sh -c 'echo $HOME')
If not, the you can get it from /etc/passwd
. There are already lots of examples of using eval
and getent
, so I'll give another option:
如果没有,您可以从/etc/passwd
. 已经有很多使用eval
and的例子了getent
,所以我会给出另一个选择:
user=pi
user_home=$(awk -v FS=':' '=="'$u'"{print }' /etc/passwd)
I would really only use that one if I had a bash script with lots of other awk oneliners and no uses of cut
. While many people like to "code golf" to use the fewest characters to accomplish a task, I favor "tool golf" because using fewer tools gives your script a smaller "compatibility footprint". Also, it's less man pages for your coworker or future-self to have to read to make sense of it.
如果我有一个带有许多其他 awk oneliner 的 bash 脚本并且不使用cut
. 虽然许多人喜欢“编码高尔夫”以使用最少的字符来完成任务,但我更喜欢“工具高尔夫”,因为使用较少的工具会使您的脚本“兼容性足迹”更小。此外,您的同事或未来的自己需要阅读以理解它的手册页更少。