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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 00:31:08  来源:igfitidea点击:

How to get $HOME directory of different user in bash script?

bash

提问by Andrew

I need to execute part of a bash script as a different user, and inside that user's $HOMEdirectory. However, I'm not sure how to determine this variable. Switching to that user and calling $HOMEdoes 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 evalapply; in this case, the assumption is that you control the value of $different_userand 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 sudoersfile can impersonate other users via sudo.
  • The following is based on the defaultconfiguration of sudo- changing its configuration can make it behave differently - see man 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 someExehappens 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 someExeeither with -ior-s- not specifying someExe ...creates an interactiveshell:

任选地,可以有一个冒充过程运行或作为通过第(n冒充)壳,由前缀someExe与任一-i-s-未指定someExe ...创建交互式壳:

  • -icreates a loginshell for someUser, which implies the following:

    • someUser's user-specific shell profile, if defined, is loaded.
    • $HOMEpoints to someUser'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.
  • -screates 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.
  • -i为 创build一个登录shell someUser,这意味着以下内容:

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

    • 没有加载shell配置文件(尽管交互式非登录shell 的初始化文件是;例如,~/.bashrc
    • 除非您还指定-H,否则模拟进程将在 中报告原始用户的主目录$HOME
    • 模拟 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 -sit is the invokinguser's environment that matters, whereas with -iit is the impersonateduser's.

调用什么 shell由“设置的 SHELL 环境变量或 passwd(5) 中指定的 shell”决定(根据man sudo)。请注意,-s重要的是调用用户的环境,而-i它是模拟用户的环境。

Note that there are platform differences regarding shell-related behavior (with -ior -s):

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

  • sudoon 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 accepts sudo -u root -s 'echo $SHELL - $USER - $HOME - $PWD'directly (no need for eval), whereas Linux doesn't (as of sudo 1.8.95p).

  • Older versions of sudoon Linux do NOT apply shell expansions to arguments passed to a shell; for instance, with sudo 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 least sudo 1.8.9p5(e.g., Ubuntu 14.04) this has been fixed. Therefore, to ensure expansion on Linux even with older sudoversions, pass the the entire command as a single argument to eval; e.g.: sudo -u root -H -s eval 'echo $HOME'. (Although not necessary on OSX, this will work there, too.)

  • The rootuser's $SHELLvariable contains /bin/shon OSX 10.9, whereas it is /bin/bashon Ubuntu 12.04.

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

  • sudoLinux 上的旧版本不将 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_COMMANDSUDO_USERSUDO_UID=SUDO_GID

See man sudoand man sudoersfor many more subtleties.

查看man sudoman sudoers了解更多细微之处。

Tip of the hat to @DavidW and @Andrew for inspiration.

向@DavidW 和@Andrew 致敬以寻求灵感。

回答by David W.

In BASH, you can find a user's $HOMEdirectory 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 $HOMEdirectory.

这将呼出 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 fooas user bob:

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

$ sudo -i -ubob -sfoo

This will start up a new shell, and the -iwill simulate a login with the user's default environment and shell (which means the foocommand 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 suhacks, or bothering with the overhead of launching another bashshell just to find the $HOMEenvironment variable...

而不是搞乱su黑客,或者打扰启动另一个bashshell的开销只是为了找到$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:

getentcan do a lot more... just see the man page. The passwdnsswitch database will return the user's entry in /etc/passwdformat. Just split it on the colon :to parse out the fields.

getent可以做更多...只需查看手册页。在passwdnsswitch的数据库将返回用户在录入/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 -uoption for sudoin this case. From the manpage:

在这种情况下,您需要该-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:

所以你想:

  1. execute part of a bash scriptas a different user
  2. change to that user's $HOME directory
  1. 以不同的用户身份执行bash 脚本的一部分
  2. 切换到该用户的 $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_pathin most cases would be /home/username

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

Assumes: You have previously set $usernamewith 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, getentwill 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 rootthen 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 evaland getent, so I'll give another option:

如果没有,您可以从/etc/passwd. 已经有很多使用evaland的例子了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. 虽然许多人喜欢“编码高尔夫”以使用最少的字符来完成任务,但我更喜欢“工具高尔夫”,因为使用较少的工具会使您的脚本“兼容性足迹”更小。此外,您的同事或未来的自己需要阅读以理解它的手册页更少。