繁体   English   中英

为什么我不能在shell脚本中使用'sudo su'? 如何自动使用sudo运行shell脚本

[英]Why can't I use 'sudo su' within a shell script? How to make a shell script run with sudo automatically

我无法弄清楚这有什么问题。 当我在终端中运行并输入密码时,没有任何反应,但如果我在终端中单独运行每个命令,它就可以工作。 谢谢!

#!/bin/bash    

sudo su;
mkdir /opt/D3GO/;
cp `pwd`/D3GO /opt/D3GO/;
cp `pwd`/D3GO.png /opt/D3GO/;
cp `pwd`/D3GO.desktop /usr/share/applications/;
chmod +x /opt/D3GO/D3GO

命令sudo su启动一个交互式root shell,但它不会将当前shell转换为root。

做你想做的事的成语就像这样(感谢@CharlesDuffy的额外注意):

#check for root
UID=$(id -u)
if [ x$UID != x0 ] 
then
    #Beware of how you compose the command
    printf -v cmd_str '%q ' "$0" "$@"
    exec sudo su -c "$cmd_str"
fi

#I am root
mkdir /opt/D3GO/
#and the rest of your commands

我们的想法是检查当前用户是否为root用户,如果没有,则用su重新运行相同的命令

您可以使用Here Documents将输入重定向到交互式shell脚本。 operator <<是读取输入的指令,直到找到包含指定分隔符的行为EOF (文件末尾)。

sudo su <<EOF
echo "code"
EOF

例如

#!/bin/bash    
sudo su <<EOF
mkdir /opt/D3GO/
cp `pwd`/D3GO /opt/D3GO/
cp `pwd`/D3GO.png /opt/D3GO/
cp `pwd`/D3GO.desktop /usr/share/applications/
chmod +x /opt/D3GO/D3GO
EOF

sudo su不是在shell中运行的命令 - 它启动一个新的shell

这种新的外壳不再运行脚本,并运行该脚本的旧壳等待新的退出后再继续。

接受的答案效果很好,但对脚本成语重新调用本身带有sudo需求可以简化更加便携

[[ $(id -u) -eq 0 ]] || exec sudo /bin/bash -c "$(printf '%q ' "$BASH_SOURCE" "$@")"
  • 使用[[ ... ]]代替[ ... ]会使x前置操作数(或双引LHS)不必要。

  • 使用bash -c而不是su -c来解释重构的命令行使命令更具可移植性,因为并非所有平台都支持su -c (例如,macOS不支持)。

  • bash$BASH_SOURCE通常是引用运行脚本的更可靠方式。


使用上述方法,参数中的任何变量引用或命令/算术替换总是由调用 shell扩展。

如果你想要延迟扩展 - 这样在sudo shell运行之前不会扩展变量引用,在root用户的上下文中 - 使用:

(( __reinvoked )) || exec sudo -s __reinvoked=1 "$BASH_SOURCE" "$@"

请注意,您必须引用包含变量引用或命令替换的任何参数,以便对它们进行延迟扩展; 例如, '$USER'

请注意使用ad-hoc环境变量__reinvoked来确保重新调用一次 (即使最初已经以root用户身份调用)。


这是演示第一种技术的示例脚本

  • 如果不以root身份调用,则脚本会使用sudo -s重新调用自身,并通过as-is传递所有参数。

  • 除非先前已经过身份验证且仍处于超时期限内,否则sudo将提示输入管理员密码。

#!/bin/bash

[[ $(id -u) -eq 0 ]] || exec sudo /bin/bash -c "$(printf '%q ' "$BASH_SOURCE" "$@")"

# Print the username and all arguments.
echo "Running as: $(id -un)"
echo "Arguments:"
for arg; do echo "  $((++i)): [$arg]"; done

acfreitas的有用答案演示了一个“脚本内部脚本”技术 ,其中here-document用于通过stdin向sudo su提供shell代码。
同样, sudo -s就足够了引用很重要

sudo -s -H <<'EOF'
echo "$HOME"
EOF

请注意如何引用此处的开头文档分隔符(在这种情况下为EOF ,以防止当前 shell对文档内容进行预先解释。
如果您没有引用( EOF任何部分), $HOME将扩展到当前用户的主目录。

如果要混合前期扩展和延迟扩展 ,请将此处的开头 - 文档分隔符不加引号和选择性\\ -quote $实例保留:

sudo -s -H <<EOF
echo "Called by: $USER; root's home dir: \$HOME"
EOF

因为运行“sudo su”会打开一个新shell,并且在退出该shell之前命令不会返回。 也许将脚本分成2个文件:第一个运行sudo并在sudo下执行第二个脚本。

sudo su将尝试以root身份启动新shell。 打开新shell后,原始脚本将不会继续,直到新shell关闭。

要修复尝试:

在shell脚本中尝试:

su <username> -c "my command"

因此,如果用户是“userA”:

su userA -c "mkdir /opt/D3GO/"

但是,如果您是userA,并且您希望以root身份运行脚本部分,则会提示您输入通行证。

su root -c "mkdir /opt/D3GO/"

您也可以通过首先使用sudo运行脚本来解决这个问题

sudo ./myScript.sh

这样,脚本会保留脚本中的原始用户,您可以使用标准变量(如$ {USERNAME}$ {UID}等)访问该脚本

取决于什么对你有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM