【问题标题】:How do I use su to execute the rest of the bash script as that user?我如何使用 su 作为该用户执行其余的 bash 脚本?
【发布时间】:2020-08-11 15:16:00
【问题描述】:

我编写了一个脚本,该脚本将一个字符串作为参数,该字符串是用户名和项目的串联。该脚本应该切换 (su) 到用户名,cd 到基于项目字符串的特定目录。

我基本上是想做的:

su $USERNAME;  
cd /home/$USERNAME/$PROJECT;  
svn update;  

问题是,一旦我做了一个 su... 它就在那里等着。这是有道理的,因为执行流程已经传递到切换到用户。一旦我退出,其余的事情就会执行,但它不能按预期工作。

我在 svn 命令前添加了 su,但命令失败(即它没有更新所需目录中的 svn)。

如何编写允许用户切换用户和调用 svn 的脚本(除其他外)?

【问题讨论】:

    标签: bash permissions sudo user-permissions su


    【解决方案1】:

    诀窍是使用“sudo”命令而不是“su”

    你可能需要添加这个

    username1 ALL=(username2) NOPASSWD: /path/to/svn
    

    到您的 /etc/sudoers 文件

    并将您的脚本更改为:

    sudo -u username2 -H sh -c "cd /home/$USERNAME/$PROJECT; svn update" 
    

    其中 username2 是您要运行 SVN 命令的用户,而 username1 是运行脚本的用户。

    如果您需要多个用户来运行此脚本,请使用 %groupname 而不是 username1

    【讨论】:

    • 我有类似的问题,但我想为其他用户运行chsh。我的问题在*.com/q/15307289/80353 中列出了我如何根据我的情况调整您的答案?
    • 我这样做了 - 但它仍然要求我输入密码。
    • @Hippyjim 你确定你的用户名正确吗?
    • 我做到了——事实证明我还需要允许使用 /bin/bash。
    • 使用sudo 还是su 是次要的,尽管sudo 更安全、更方便。
    【解决方案2】:

    改用sudo

    编辑:正如 Douglas 指出的,您不能在 sudo 中使用 cd,因为它不是 外部 命令。您必须在子 shell 中运行命令才能使 cd 工作。

    sudo -u $USERNAME -H sh -c "cd ~/$PROJECT; svn update"
    

    罢工>

    sudo -u $USERNAME -H cd ~/$PROJECT
    sudo -u $USERNAME svn update
    

    您可能会被要求输入该用户的密码,但只能输入一次。

    【讨论】:

    • 这行不通 - 在第一个 sudo 执行完成后 cd 将丢失。
    • 其实连cd都不能直接调用,因为它不是external命令。
    • sudo 可能很方便,但如果它不是开箱即用的(就像在 AIX 上一样),那就不好了。 su -c 'commands' 是正确答案。
    【解决方案3】:

    您需要将所有不同用户的命令作为他们自己的脚本来执行。如果它只是一个或几个命令,那么内联应该可以工作。如果命令很多,那么最好将它们移动到自己的文件中。

    su -c "cd /home/$USERNAME/$PROJECT ; svn update" -m "$USERNAME" 
    

    【讨论】:

    • 这是唯一正确的答案。 sudo 不是必需的。
    • 您可能还需要为 shell 提供su -s /bin/bash
    • root 用户的最佳解决方案
    • 默认情况下没有安装sudo的人的最佳答案(我在看你AIX)
    【解决方案4】:

    无法在 shell 脚本中更改用户。其他答案中描述的使用 sudo 的解决方法可能是您最好的选择。

    如果你很生气以 root 身份运行 perl 脚本,你可以使用 $< $( $> $) 保存真实/有效 uid/gid 的变量来执行此操作,例如:

    #!/usr/bin/perl -w
    $user = shift;
    if (!$<) {
        $> = getpwnam $user;
        $) = getgrnam $user;
    } else {
        die 'must be root to change uid';
    }
    system('whoami');
    

    【讨论】:

    • -1 因为它 IS 可以使用 sudo 临时获得其他用户的权限。
    • 从某种意义上说,shell 脚本本身运行的用户无法更改(这是原始问题所要求的),这是不可能的。使用 sudo 调用其他进程不会改变脚本本身的运行身份。
    【解决方案5】:

    使用如下脚本在另一个用户下执行其余或部分脚本:

    #!/bin/sh
    
    id
    
    exec sudo -u transmission /bin/sh - << eof
    
    id
    
    eof
    

    【讨论】:

    • 你可能想使用“sudo -i -u ...”来确保像 $HOME 这样的东西设置正确。
    • 对不起菜鸟问题,但这里的 id 是什么?
    • @NitinJadhav,他在这里使用它只是为了显示当前用户的 ID,root 的 ID 是 0,所以第一个 id 会显示一些数字,但第二个会明确显示 0 (因为第二个是在 root 运行的块内执行的)。您可以使用 whoami 而不是 id ,这将返回名称而不是 id
    • @MohammedNoureldin 谢谢!
    • sudo 可能很方便,但如果它不是开箱即用的(就像在 AIX 上一样),那就不好了。 su -c 'commands' 是正确答案。
    【解决方案6】:

    更简单:使用sudo 运行shell,使用heredoc 为其提供命令。

    #!/usr/bin/env bash
    whoami
    sudo -i -u someuser bash << EOF
    echo "In"
    whoami
    EOF
    echo "Out"
    whoami
    

    (回答originally on SuperUser

    【讨论】:

    • 这个答案效果最好。我建议使用选项-i 来获得someuser 的预期环境。
    • sudo 可能很方便,但如果它不是开箱即用的(就像在 AIX 上一样),那就不好了。 su -c 'commands' 是正确答案。
    • 史诗般的解决方案!
    • 如何让变量在 herdoc 的范围内可用?
    • @DJ_Stuffy_K:没关系。您只需要输入当前登录用户的密码,该用户需要root权限。见differences between sudo and su
    【解决方案7】:

    这对我有用

    我将“供应”从“启动”中分离出来。

     # Configure everything else ready to run 
      config.vm.provision :shell, path: "provision.sh"
      config.vm.provision :shell, path: "start_env.sh", run: "always"
    

    然后在我的 start_env.sh 中

    #!/usr/bin/env bash
    
    echo "Starting Server Env"
    #java -jar /usr/lib/node_modules/selenium-server-standalone-jar/jar/selenium-server-standalone-2.40.0.jar  &
    #(cd /vagrant_projects/myproj && sudo -u vagrant -H sh -c "nohup npm install 0<&- &>/dev/null &;bower install 0<&- &>/dev/null &")
    cd /vagrant_projects/myproj
    nohup grunt connect:server:keepalive 0<&- &>/dev/null &
    nohup apimocker -c /vagrant_projects/myproj/mock_api_data/config.json 0<&- &>/dev/null &
    

    【讨论】:

      【解决方案8】:

      这是另一种方法,在我的情况下更方便(我只是想放弃 root 权限并从受限用户执行我的脚本的其余部分):您可以让脚本从正确的用户重新启动。假设它最初以 root 身份运行。然后它看起来像这样:

      #!/bin/bash
      if [ $UID -eq 0 ]; then
        user=$1
        dir=$2
        shift 2     # if you need some other parameters
        cd "$dir"
        exec su "$user" "$0" -- "$@"
        # nothing will be executed beyond that line,
        # because exec replaces running process with the new one
      fi
      
      echo "This will be run from user $UID"
      ...
      

      【讨论】:

      • 我想知道为什么这不是更高的评价。它最好地解决了原始问题,同时将所有内容都保留在 bash 中。
      • runuser -u $user -- "$@",如su(1)中所述
      • 是的,runuser 可以在相反的情况下使用 - 即放弃 root 特权。
      • exec su "$user" "$0" -- "$@"
      • 谢谢@macieksk,不错的收获。会更新。 -- 真的很有用。
      【解决方案9】:

      受到@MarSoft 的想法的启发,但我更改了如下几行:

      USERNAME='desireduser'
      COMMAND=$0
      COMMANDARGS="$(printf " %q" "${@}")"
      if [ $(whoami) != "$USERNAME" ]; then
        exec sudo -E su $USERNAME -c "/usr/bin/bash -l $COMMAND $COMMANDARGS"
        exit
      fi
      

      我使用sudo 来允许少密码执行脚本。如果要为用户输入密码,请删除 sudo。如果您不需要环境变量,请从 sudo 中删除 -E

      /usr/bin/bash -l 确保 profile.d 脚​​本针对已初始化的环境执行。

      【讨论】:

      • sudo 可能很方便,但如果它不是开箱即用的(就像在 AIX 上一样),那就不好了。 su -c 'commands' 是正确答案。
      • @Tricky 也许阅读完整的答案,它已经建议删除sudo。事实上,sudo 并不是那么简单,在很多情况下,您甚至需要 sudo -E 和 sudoers.d 中的配置条目,以允许在不使用 !requiretty 的 tty 的情况下执行。但是在很多情况下,自动调用脚本需要 sudo,而密码对话框可能会干扰。因此,我不会将其从标准解决方案中删除。
      • 有问题的代码完全是错误的——它会用空格破坏脚本名称或参数;请记住,将"$@" 放在字符串中意味着将第一个参数之后的参数附加到单独的字符串中,包含在-c 参数中。如果你想让它安全,你可以printf -v arg_q '%q ' "$0" "$@" 然后使用su "$USERNAME" -c "/usr/bin/bash -l $arg_q"
      • @CharlesDuffy 你是对的!我为这个答案简化了我的生产脚本:-( 只需添加一个COMMANDARGS=$@ 就可以解决-c 的问题。带空格的参数以前不是问题,但我实现了你的良好输入。我只需要做一些实验让它工作。我已经编辑了这个问题,希望我没有粘贴另一个错误。感谢您的评论,羞辱但必要。
      最近更新 更多