如何在脚本中使用sudo命令而无需输入密码?

我想每天自动启动我的系统。所以我在我的Python脚本中使用了下面的代码,但是sudo每次都要求我输入密码:
os.system('sudo sh -c "echo date \'+%s\' -d \'+ \
       24 hours\' > /sys/class/rtc/rtc0/wakealarm"')

如何在不每次都要求输入密码的情况下运行这个脚本?

4你应该查看主板手册或BIOS,看看它是否支持这种行为。我知道这是推诿问题!=] 但这可能是一个足够的解决方案。 - Alex Hirzel
5个回答

请注意:任何将登录密码以明文形式放入命令或文件中的方法都是不安全的,请不要使用sudo 的正确使用方式是设置仅允许运行一个特定命令,例如 echo date... > rtc...,而无需输入密码。

步骤 1. 创建一个只包含该命令的 shell 脚本

  • 打开gedit(或您喜欢的编辑器),并创建脚本,例如pydatertc.sh
  • 只插入这一行,并将其保存到您的主目录中,例如:
    echo date \'+%s\' -d \'+ 24 hours\' > /sys/class/rtc/rtc0/wakealarm
  • 退出编辑器,并从终端中使脚本可执行并且更改其所有权为root,否则可以访问您系统的另一个用户可能会编辑它并以root身份执行任何命令而无需输入密码:
    sudo chown root:root /home/username/pydatertc.sh
    sudo chmod 700 /home/username/pydatertc.sh
    

第二步:设置sudo允许pydatertc.sh在不需要密码的情况下执行

  • 在终端中输入sudo visudo以打开sudo权限(sudoers)文件
  • 大约在第25行附近,您会看到这一行:%sudo ALL=(ALL:ALL) ALL
  • 在该行下方插入以下行,其中username是您的用户名:
    username  ALL=(ALL) NOPASSWD: /home/username/pydatertc.sh
  • 退出编辑器(如果使用nano,则按Ctrl+X

第三步:修改您的Python脚本以调用pydatertc.sh

  • 将以下行更改为:
    os.system('sudo /home/username/pydatertc.sh')

现在,您的脚本应该可以在不需要密码的情况下运行,并且不会危及您的账户、数据或系统的安全性!


仅适用于wakealarm的替代方法(不适用于一般情况!):

仅限于这种特定情况下,由于/sys/class/rtc/rtc0/wakealarm文件仅控制系统的唤醒闹钟,并且没有其他危害,另一种避免密码的替代方法是使用chown获取该文件的所有权(如果您是唯一设置闹钟的用户),或者使用chmod +666使其对所有人可写;在这种情况下,只需从Python调用中删除sudo,保留sh -c "...."即可。


1太棒了,这就是正确的做法。 - roadmr
1这是一个非常详细、有帮助的回答,而且恰好是应该做的方式。 - ArtOfCode
@RobertRosati,非常感谢你的建议修改 - 我不应该一开始就忘记了! - ish
chmodchown真的需要吗? - m-ric
1@m-ric 你有没有读到上面这几行的指令?“否则,其他有权限访问你系统的用户可能会编辑它并以root身份执行任何命令,而无需输入你的密码。” - Tobias Kienzler
我尝试执行以下操作: #!/usr/bin/env python _ import os _
os.system('sudo bash /apps/myapp') 但是现在我的Python脚本要求输入密码。:( 为什么会这样?
- Bee
5我意识到这个答案很旧 - 但是这里仍然存在一个问题:如果文件位于**/home/username,那么如果该目录可被恶意用户(或已被入侵的非根登录)写入,则系统可能会受到损害。他们可以删除或重命名文件,将另一个脚本放在原来的位置,并通过sudo运行该脚本 - 而无需密码。因此,将脚本放到只有root可以更改的目录中,例如/usr/sbin/root**,会更加安全。否则,一切都很好。 - NVRAM
嗨,我需要打开这个文件“/dev/input/event3”。 我用Python中的“open(myfile,“r”)”来做到这一点。问题是-如你所料-我需要提升特权才能读取此文件。除此之外,我无法将这行单独的代码放在一个单独的文件中,然后将其添加到visudo中,因为我需要不断地读取此文件的内容。你有什么建议? - traducerad
你能解释一下wakealarm文件中的date '+%s' -d '+ 24 hours'是做什么的吗?这个链接解释了wakealrm的作用。这个过程适用于Ubuntu 16.04及更高版本的系统吗? - Sun Bear

警告!

将您的登录密码以明文形式放在命令或文件中是极其不安全的,可能会危及您的私人数据和系统。强烈建议即使您认为您的系统是“个人”或位于“安全位置”,也绝对不要这样做!

如果脚本仅供个人使用,并且您已将其放置在安全的位置,并且不担心您的帐户被盗等情况,那么这里有一个简单的解决方案:

echo LOGINPASSWD | sudo -S COMMAND HERE

LOGINPASSWD是您的登录密码(例如:iloveponies),COMMAND HERE是在sudo之后的命令,例如sh -c "echo da..等等


15@Viswa,请注意,以明文形式透露密码非常危险。强烈建议您不要这样做。 - Anwar
3如果这听起来像个好主意,你最好还是在你的根账户上设置一个密码,并使用z7sg的解决方案;这样做同样简单,而且不会产生这个非常危险的安全问题。 - Bryce
2谢谢,不过现在我知道了如何在运行sudo命令时不需要输入密码。与此同时,我也明白了显示密码的问题。 - Viswa
4哈!我的回答得到了6个赞和4个踩 :) 但是,伙计们,为什么呢?我不是说得很清楚吗,“个人使用”,“安全地方”等等?除非你把这个文件分享出去并且你的SSH服务器正在运行,否则就没有安全问题!既然这个脚本是用于个人使用并且放在安全的地方,你从哪里看出了安全问题呢? - hytromo
6被踩了,这是通往黑暗面的道路,并且在使用sudo方法时并不需要。 - Floyd
4好的,告诉我吧,即使黑客以普通用户身份登录到您的帐户,他又如何在 /usr/share/help/lv/ubuntu-help 目录下找到带有您密码的脚本呢? - hytromo
2这是这里最好的答案。不仅适用于特定问题,还适用于以非交互方式运行sudo的一般问题。 - HappyFace
我需要在一个单独的终端窗口中以超级用户身份启动另一个进程,并让它在后台运行。为了避免明文输入密码,我使用getpass.getpass()从提示中获取密码,这一切都非常顺利。谢谢! - Shiva

如果您不介意脚本在整点(或白天)特定时间运行,请将其放在root用户的主目录(/root)中,并以root身份从系统crontab(/etc/crontab)运行脚本。这样,您就不必牺牲安全性。
请参阅https://help.ubuntu.com/community/CronHowto了解如何将脚本添加到crontab中。

4如果你的电脑是桌面或笔记本,不是全天候运行的话,你可能想使用anacron - balki
这是一个有用的答案,例如,如果您正在编写脚本来检查更新、对此信息进行处理并通过电子邮件通知管理员所需的更新,那么它非常实用。就个人而言,我使用许多脚本来进行服务器自动化,所以我倾向于只使用"sudo crontab -e"命令。+1 - Rab

另一个与sudo相关的好功能是“timestamp_timeout”变量,这在上面的出色答案中没有提到。它是一个sudo变量,您可以增加它以减少交互式密码输入的次数。
例如,在/etc/sudoers(或其中一个包含的文件)中,您可以修改默认值:
# only require a password once every 60 minutes
Defaults timestamp_timeout=60

'man sudoers'的完整描述:

timestamp_timeout

        Number of minutes that can elapse before sudo will ask for
        a passwd again.  The default is 5, set this to 0 to always
        prompt for a password.
当然,在从cron运行命令的特定情况下,这是无济于事的。但是意识到这一点是很好的。

export MY_SUDO_PASS="user_password_here"

要测试是否正常工作,请输入以下内容:
echo $MY_SUDO_PASS
> user_password_here

要运行“sudo apt-get update”,并接受之前创建的环境变量中的密码:
echo $MY_SUDO_PASS | sudo -S apt-get update

从Python中运行(例如递归更改目录所有权为username_here):
python
>> import subprocess
>> subprocess.call('echo $MY_SUDO_PASS | sudo -S chown -R username_here /home/username_here/folder_to_change_ownership_recursivley', shell=True)

echo $MY_SUDO_PASS 获取密码 -S 开关捕获并将密码传递给 sudo


对于现有答案来说,我不确定这个问题有何增益。目前的BIOS支持根据闹钟唤醒功能... - Elder Geek