我正在编写shell脚本,其中经常写一些东西
到一个文件,然后执行一个读取该文件的应用程序。我发现,通过我们公司,网络延迟差别很大,因此简单的sleep 2
例如不够健壮。
我尝试编写一个(可配置的)超时循环,如下所示:
waitLoop()
{
local timeout=$1
local test="$2"
if ! $test
then
local counter=0
while ! $test && [ $counter -lt $timeout ]
do
sleep 1
((counter++))
done
if ! $test
then
exit 1
fi
fi
}
适用于test="[ -e $somefilename ]"
。但是,测试存在是不够的,我有时需要测试某个字符串是否写入文件。我试过了
test="grep -sq \"^sometext$\" $somefilename"
,但这不起作用。有人可以告诉我为什么吗?
是否还有其他更简洁的选项来执行此类测试?
答案 0 :(得分:1)
您可以这样设置测试变量:
test=$(grep -sq "^sometext$" $somefilename)
你的grep
无法正常工作的原因是引号很难在参数中传递。您需要使用eval
:
if ! eval $test
答案 1 :(得分:0)
我会说 检查文本文件中字符串的方法是grep。
你的确切问题是什么?
您也可以调整NFS挂载参数,以消除根本问题。同步也可能有所帮助。请参阅NFS文档。
答案 2 :(得分:0)
如果您想在“if”中使用waitLoop,您可能希望将“exit”更改为“return”,因此脚本的其余部分可以处理错误情况(甚至没有消息用户在脚本死之前失败的原因。)
另一个问题是使用“$ test”来保存命令意味着你在实际执行时没有得到shell扩展,只是评估。所以,如果你说test =“grep \”foo \“\”bar baz \“”,而不是在七个字符名称baz的文件中查找三个字母的字符串foo,它将查找五个字符串“foo”中的九个char文件“bar baz”。
所以你可以决定你不需要shell魔法,并设置test ='grep -sq ^ sometext $ somefilename',或者你可以让shell明确地处理引用:
if /bin/sh -c "$test"
then
...
答案 3 :(得分:0)
尝试使用文件修改时间来检测何时写入而不打开它。像
这样的东西old_mtime=`stat --format="%Z" file`
# Write to file.
new_mtime=$old_mtime
while [[ "$old_mtime" -eq "$new_mtime" ]]; do
sleep 2;
new_mtime=`stat --format="%Z" file`
done
但是,如果多个进程同时尝试访问该文件,则无效。
答案 4 :(得分:0)
我刚才遇到了同样的问题。我对你在OP中包含的超时等待采用了类似的方法;但是,我还包括一个文件大小的检查。如果文件自上次检查后文件大小增加,我会重置我的超时计时器。我正在写的文件可能只有几个,所以他们需要一段时间来编写NFS。
对于您的特定情况,这可能有点过分,但我的写作过程也会在完成写入后计算文件的哈希值。我使用的是md5,但是像crc32这样的东西也可以使用。这个哈希从作者广播到(多个)读者,并且读者等待直到a)文件大小停止增加和b)文件的(新计算的)哈希与写入者发送的哈希相匹配。
答案 5 :(得分:0)
我们有类似的问题,但出于不同的原因。我们正在读取s文件,该文件被发送到SFTP服务器。运行脚本的计算机不是SFTP服务器。
我所做的是在cron中设置它(虽然一个带睡眠的循环也可以工作)来做一个文件的cksum。当旧的cksum与当前的cksum匹配时(文件在确定的时间内没有改变),我们知道写入完成,并传输文件。
为了更加安全,我们永远不会在进行备份之前覆盖本地文件,并且只在远程文件在一行中有两个匹配的cksum并且cksum与本地文件不匹配时才传输。
如果您需要代码示例,我相信我可以将它们挖掘出来。
答案 6 :(得分:0)
shell将你的谓词分成单词。使用$@
抓取所有内容,如下面的代码所示:
#! /bin/bash
waitFor()
{
local tries=$1
shift
local predicate="$@"
while [ $tries -ge 1 ]; do
(( tries-- ))
if $predicate >/dev/null 2>&1; then
return
else
[ $tries -gt 0 ] && sleep 1
fi
done
exit 1
}
pred='[ -e /etc/passwd ]'
waitFor 5 $pred
echo "$pred satisfied"
rm -f /tmp/baz
(sleep 2; echo blahblah >>/tmp/baz) &
(sleep 4; echo hasfoo >>/tmp/baz) &
pred='grep ^hasfoo /tmp/baz'
waitFor 5 $pred
echo "$pred satisfied"
输出:
$ ./waitngo [ -e /etc/passwd ] satisfied grep ^hasfoo /tmp/baz satisfied
打字稿并不像实时观看那样有趣。
答案 7 :(得分:-1)
好的...这有点令人讨厌......
如果您可以控制文件:您可以在此处创建“命名管道”。 所以(取决于编写程序的工作方式),您可以以同步方式监视文件。
最简单的方法:
创建命名管道:
mkfifo file.txt
设置同步接收器:
while :
do
process.sh < file.txt
end
创建测试发件人:
echo "Hello There" > file.txt
'process.sh'是您的逻辑所在的位置:这将阻塞,直到发送方写入其输出。从理论上讲,作家程序不需要修改....
警告:如果接收器由于某种原因未运行,您最终可能会阻止发件人!
不确定它符合您的要求,但可能值得研究。
或者为避免同步,请尝试'lsof'?
http://en.wikipedia.org/wiki/Lsof
假设您只想在没有其他内容写入时从文件中读取(即写入过程已完成) - 您可以检查是否有其他文件处理它?</ p>