在bash脚本中使用sudo的最佳实践

我有一个漫长而长时间运行的bash脚本,其中一些命令需要以root身份运行,而大多数命令需要在sudo之前作为普通用户运行,因为它会弄乱文件所有权等等。

我提出了一些方法,但每个方法都有一些问题

方法1:在文件中使用sudo

#!/bin/bash sudo echo "I must be run by root" touch needsToBeOwnedByUser1 echo "needs to be run by user" sleep 1000 sudo echo "I, again, must be run by root" 

从编写代码的方式来看,这看起来很好。 sudo是在root之前实际需要运行的几个语句之前编写的,但是如果每次sudo调用之间的时间太长, sudo再次要求输入密码。 此外,如果第一次执行sudo失败,例如由于密码无效,则仍会执行脚本的其余部分。

方法2:使用sudo调用文件,然后在需要时更改回原始用户

 #!/bin/bash echo "I must be run by root" su username -c 'touch needsToBeOwnedByUser1' su username -c 'echo "needs to be run by user"' su username -c 'sleep 1000' echo "I, again, must be run by root" 

这也很糟糕,因为我需要在几乎每行前面添加su username -c 。 也可以在sudo之后找到原始用户名,但很麻烦。

有没有更好的办法?

编辑:我只在这里发布了一些小的,荒谬的脚本来展示我在说什么。 在实际的脚本中,我有一些需要sudo(启动和停止服务)的行,有些行如果有sudo并且真的需要在没有sudo的情况下运行很多行并不重要。

关于方法2,使用函数更容易。 例如:

 #!/bin/bash func(){ echo "Username: $USER" echo " EUID: $EUID" } export -f func func su "$SUDO_USER" -c 'func' 

$SUDO_USER是sudoer的用户名。 您也可以在其位置使用$(logname)

在我的机器上运行:

 $ sudo bash test.sh [sudo] password for wja: Username: root EUID: 0 Username: wja EUID: 1000 

通过阅读man sudoers ,人们看到:

  PASSWD and NOPASSWD By default, sudo requires that a user authenticate him or herself before running a command. This behavior can be modified via the NOPASSWD tag. Like a Runas_Spec, the NOPASSWD tag sets a default for the commands that follow it in the Cmnd_Spec_List. Conversely, the PASSWD tag can be used to reverse things. For example: ray rushmore = NOPASSWD: /bin/kill, /bin/ls, /usr/bin/lprm would allow the user ray to run /bin/kill, /bin/ls, and /usr/bin/lprm as root on the machine rushmore without authenticating himself. 

因此,您可以允许主机machine1上的regular操作以root身份执行command1command2而无需使用以下密码进行身份validation:

 reguser machine1 root = NOPASSWD: /usr/local/command1, /usr/local/command2 

但请阅读man -k sudo每一个细节。