2011-08-18 54 views
1

我有一个脚本,我的意思是从cron运行,确保我写的守护进程正在工作。该脚本文件的内容类似于以下内容:为什么在脚本中使用反引号执行的命令会给我不同的结果?

daemon_pid=`ps -A | grep -c fsdaemon` 
echo "daemon_pid: " $daemon_pid 
if [ $daemon_pid -eq 0 ]; then 
    echo "restarting fsdaemon" 
    /etc/init.d/fsdaemon start 
fi 

当我从命令提示符下执行这个脚本,呼应的$ daemon_pid值报告为2的值,该值是二不管线路我的守护进程是否在运行。但是,如果我用反引号执行该命令,然后检查$ daemon_pid变量,那么$ daemon_pid的值现在为1。我也尝试过使用bashdb单步执行脚本,当我使用该工具检查变量时,他们应该是。

因此,我的问题是:为什么在shell执行脚本时与手动执行脚本中的命令之间存在行为差异?我敢肯定,我缺少一些非常重要的东西。

+2

只是为了检查显而易见的:脚本文件的名称不包含'fsdaemon',是吗? –

+0

事实上,脚本文件的名称是“check-fsdaemon”。这也许是一个重要的原因(我看到两个)。另一个来自命令行的grep? –

+0

另外,'grep'进程的参数列表中有'fsdaemon'。你可以不用'-c'来验证它。 –

回答

3

您很可能会遇到grep作为ps的“答案”的一部分。

为了帮助完全理解正在发生的事情,请关闭-c选项,以查看仅从ps -A | grep fsdameon返回的数据。

为了解决这个问题,一些系统有一个p(rocess)grep(pgrep)。这将工作,或

ps -A | grep -v grep | grep -c fsdaemon 

是一个常见的习惯用法,你会看到,但在牺牲另一个进程。

的干净的解决方案是,

ps -A | grep -c '[f]sdaemon' 

的正则表达式语法应与所有工作里grep,在所有系统上。

我希望这会有所帮助。

+0

我真的很喜欢pgrep命令,它在debian 5下支持。谢谢。 –

+0

根据我的测试,似乎'grep'找到反引号产生的子进程 - 它实际上并没有发现它自己,因为'ps -A'没有列出命令行参数。 –

+0

感谢您的洞察力。我通常使用'ps -ef'或'ps auexww',但将'ps -A'留作我答案的一部分,因为这是OP的用法。祝你们好运。 – shellter

3

问题是grep的本身就说明了...尝试grep的-c后运行与任何命令:

eple:~ erik$ ps -a | grep -c asdfladsf 
1 
eple:~ erik$ ps -a | grep -c gooblygoolbygookeydookey 
1 
eple:~ erik$ 

什么ps -a | grep fsdaemon回报?只要看看实际列出的进程... :)

1

包含该名称的参数的aany进程将添加到计数 - grep和您的脚本。

ps ing for a process is not really reliable,you should use a lock file。

2

既然这是Linux,为什么不试试pgrep?这为您节省了一个管道,并且您不会以grep报告守护进程脚本本身的运行结束。

0

由于有几个人已经指出,因为ps | grep检测到(1)脚本本身和(2)反引号创建的子进程,它继承了主脚本的名称,所以您的进程数量被夸大了。所以一个简单的解决方案是将脚本的名称更改为不包含您要查找的名称的名称。但你可以做得更好。

我建议的“最佳实践”解决方案是使用操作系统提供的工具。初始化脚本创建一个PID文件作为启动守护进程的一部分并不罕见;换句话说,不是只运行守护进程本身,而是使用启动守护进程的包装脚本,然后将进程ID写入某个文件中。如果不存在您的系统上start-stop-daemon(我认为这是这些天很常见),你可以使用像这样:

start-stop-daemon --start --quiet --background \ 
    --make-pidfile --pidfile /var/run/fsdaemon.pid -- /usr/bin/fsdaemon 

(显然取代路径/usr/bin/fsdaemon如适用)来启动它,然后

start-stop-daemon --stop --quiet --pidfile /var/run/fsdaemon.pid 

停止它。 start-stop-daemon还有其他可能对您有用的选项,您可以通过阅读手册页进行调查。

如果您没有访问start-stop-daemon,你可以写一个包装脚本来执行基本相同的事情,像这样开始:

echo "$$" > /var/run/fsdaemon.pid 
exec /usr/bin/fsdaemon 

,这阻止:

kill $(< /var/run/fsdaemon/pid) 
rm /var/run/fsdaemon.pid 

(当然这很粗糙,但它通常应该可以正常工作)。

无论如何,一旦你的设置来生成一个PID文件,是否使用start-stop-daemon与否,你可以更新你的check脚本来此:

daemon_pid=`ps --no-headers --pid $(< /var/run/fsdaemon.pid) | wc -l` 
if [ $daemon_pid -eq 0 ]; then 
    echo "restarting fsdaemon" 
    /etc/init.d/fsdaemon restart 
fi 

(人会想到会有简短的命令检查给定的PID是否正在运行,但我不知道它)。

如果你不想(或不能)创建一个PID文件,我至少会建议pgrep代替ps | grep,因为pgrep将名义直接搜索的过程,并不会发现任何东西,只是恰好包含相同的字符串。

daemon_pid=`pgrep -x -c fsdaemon` 
if [ $daemon_pid -eq 0 ]; then 
    echo "restarting fsdaemon" 
    /etc/init.d/fsdaemon restart 
fi 

-x手段 “严丝合缝”,并-c作品与grep

顺便说一下,当它实际上是一个计数时,命名变量daemon_pid似乎有点误导。

相关问题