Answers:
您可以设置一个在后台运行的循环,以定期执行“ sudo -v”,当然,要诀就是让循环在脚本终止时完全终止。因此,两个过程之间必须进行某种类型的通信。tmp文件可以解决此问题,并且在脚本运行后也可以轻松清除它们。(无论如何,安装脚本通常都会执行此操作。)
例如(删除“ echo”语句以使用它;这些只是将其显示为“有效”):
#!/bin/bash
log=running_setup.txt
sudo_stat=sudo_status.txt
echo "========= running script $$ ========"
echo $$ >> $sudo_stat
trap 'rm -f $sudo_stat >/dev/null 2>&1' 0
trap "exit 2" 1 2 3 15
sudo_me() {
while [ -f $sudo_stat ]; do
echo "checking $$ ...$(date)"
sudo -v
sleep 5
done &
}
echo "=setting up sudo heartbeat="
sudo -v
sudo_me
echo "=running setup=" | tee $log
while [ -f $log ]
do
echo "running setup $$ ...$(date) ===" | tee -a $log
sleep 2
done
# finish sudo loop
rm $sudo_stat
然后,您将看到...(注意:pid被放入tmp文件中,只是为了您可以轻松地将其杀死。不过,这不是必需的):
$ ./do_it.sh
========= running script 6776 ========
=setting up sudo heartbeat=
[sudo] password for user:
=running setup=
checking 6776 ...Wed May 4 16:31:47 PDT 2011
running setup 6776 ...Wed May 4 16:31:48 PDT 2011 ===
running setup 6776 ...Wed May 4 16:31:50 PDT 2011 ===
running setup 6776 ...Wed May 4 16:31:52 PDT 2011 ===
checking 6776 ...Wed May 4 16:31:53 PDT 2011
running setup 6776 ...Wed May 4 16:31:54 PDT 2011 ===
<ctrl-c> (cleans up files, then exits)
我喜欢michael_n的答案,但最不理智的愿望是不使用临时文件。也许这可以提供一些观点。
我的解决方案是:
#!/bin/bash
function sudo_ping() {
if [[ ! -z $SUDO_PID ]]; then
if [[ $1 -eq stop ]]; then
echo "Stopping sudo ping in PID = $SUDO_PID"
kill $SUDO_PID
return
else
echo "Already sudo pinging in PID = $SUDO_PID"
return
fi
fi
echo "Starting background sudo ping..."
sudo -v
if [[ $? -eq 1 ]]; then
echo "Oops, wrong password."
return
fi
sudo echo "ok"
while true; do
echo 'Sudo ping!'
sudo -v
sleep 1
done &
SUDO_PID=$!
sudo echo "Sudo pinging in PID = $SUDO_PID"
# Make sure we don't orphan our pinger
trap "sudo_ping stop" 0
trap "exit 2" 1 2 3 15
}
sudo_ping
sleep 5
echo "Goodbye!"
同样,echo
的是无关紧要的...
$ ./sudoping.sh
Starting background sudo ping...
Password:
ok
Sudo ping!
Sudo pinging in PID = 47531
Sudo ping!
Sudo ping!
Sudo ping!
Sudo ping!
Goodbye!
Stopping sudo ping in PID = 47531
同样,ctrl-c也可以工作...
$ ./sudoping.sh
Starting background sudo ping...
ok
Sudo ping!
Sudo pinging in PID = 47599
Sudo ping!
^CStopping sudo ping in PID = 47599
基于这个要点,我制作了一个简洁明了的版本:
# Prevent sudo timeout
sudo -v # ask for sudo password up-front
while true; do
# Update user's timestamp without running a command
sudo -nv; sleep 1m
# Exit when the parent process is not running any more. In fact this loop
# would be killed anyway after being an orphan(when the parent process
# exits). But this ensures that and probably exit sooner.
kill -0 $$ 2>/dev/null || exit
done &
sudo -K
在shell脚本的其他位置调用该版本,则您的版本sudo: a password is required
每分钟都会对stderr 吼叫。
根据sudo
手册页:
-v If given the -v (validate) option, sudo will update the user's time stamp,
prompting for the user's password if necessary. This extends the sudo timeout for
another 15 minutes (or whatever the timeout is set to in sudoers) but does not run
a command.
因此,我想如果您sudo -v
在设置脚本的更多点添加内容以验证会话(不仅是在开始时),您将得到所需的内容,因为每次都将增加超时时间(它只会再次询问密码是否超时)。唯一的问题是脚本上的命令所花费的时间是否超过超时时间(因此,即使您在此之后立即进行验证,超时也会在完成另一个验证之前过期),但这是一个非常特殊的情况。
发生的事情是仅使用sudo
不会增加超时,sudo -v
也不会执行命令,因此您必须花费sudo -v
更多时间来验证会话。
根据格雷戈里·珀金斯(Gregory Perkins)提供的要旨和我的经验,这是我的一句话:
trap "exit" INT TERM; trap "kill 0" EXIT; sudo -v || exit $?; sleep 1; while true; do sleep 60; sudo -nv; done 2>/dev/null &
要么
trap "exit" INT TERM
trap "kill 0" EXIT
sudo -v || exit $?
sleep 1
while true; do
sleep 60
sudo -nv
done 2>/dev/null &
trap "exit" INT TERM; trap "kill 0" EXIT
:这将删除退出或SIGINT / SIGTERM的整个过程树。
sudo -v || exit $?
:预先要求输入密码并缓存安全凭证,但不要运行命令。如果密码不正确,请退出sudo返回的代码。
sleep 1
:稍微延迟一下,以便有效保存安全凭证。如果下一个sudo运行得太早,由于凭据尚未保存,它将不知道,因此将再次要求输入密码。
while true; do sleep 60; sudo -nv; done 2>/dev/null &
:重复更新现有的sudo安全凭证。请注意,此版本不同于链接的要点:首先运行sleep 60
,然后运行sudo -nv
。
该&
运营商把整个while
循环进入后台,运行它作为一个子进程。
该2>/dev/null
重定向的标准错误while
循环到空隙,所以通过在循环内的任何命令生成的错误消息将被丢弃。
所述-n
的选项sudo
,如果需要密码防止它提示用户输入密码,但显示错误消息并退出。
kill -0 "$$" || exit
链接的要点中没有,因为前两个trap
将完成工作。在确定父进程未运行之前,它无需休眠59秒钟!