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

我无法弄清楚这有什么问题。 当我在terminal中运行它并input密码时,什么都不会发生,但是如果我在terminal中单独运行每个命令,它都会起作用。 谢谢!

#!/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启动一个交互式的根shell,但是它不会将当前的shell转换为一个根shell。

做你想做的事情的成语是这样的(感谢@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重新运行相同的命令

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

新的shell不再运行你的脚本,运行这个脚本的旧shell等待新脚本退出,然后继续运行。

您可以使用“这些文档”将输入重定向到交互式shell脚本。 运算符<<是读取输入的指令,直到找到包含指定分隔符的行为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按需求重新调用脚本习惯用法,并使其更加便携

 [[ $(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重新调用自身,按原样传递所有参数。

  • 除非先前已经过认证,并且在超时期限内, 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的有用答案演示了一个“script- in -a-script”技术 ,其中一个here-document被用来通过stdin提供shell代码给sudo su
再次, sudo -s就足够了引用是很重要的

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

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

如果你想混合预先和延迟扩展 ,留下这里的开放 – 文档分隔符不加引号,并有选择地\ quoted $实例:

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

由于运行“sudo su”会打开一个新的shell,并且该命令在您退出该shell之前不会返回。 也许将脚本分成两个文件:第一个运行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}等标准变量来访问脚本

取决于什么对你更好。