2009-07-03 77 views
6

我正在編寫shell腳本,其中經常將一些東西寫入文件 ,之後執行讀取該文件的應用程序。我發現通過我們公司的網絡延遲差異很大,所以例如簡單的sleep 2將不夠健壯。如何處理shell腳本中的NFS延遲

我試着寫一(配置)超時循環是這樣的:

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

是否可以簡單地在文件上運行尾部,並只檢查尾部的輸出(即最後一行)? 這假設尾巴更聰明地檢查然後你的腳本檢查文件何時更改(機會是,尾巴以更合適的方式) – nos 2009-07-03 15:14:00

+0

我認爲正確的方法將取決於「有些東西」是什麼以及什麼「應用程序」是。你能否提供你想要解決的實際問題的更多細節?所寫的問題有點模糊;可能會有完全不同的方法,你沒有想到。 – 2009-12-20 09:15:40

+0

看到我編輯的答案。 – 2009-12-24 00:44:46

回答

1

您可以設置測試變量是這樣的:

test=$(grep -sq "^sometext$" $somefilename) 

grep不工作的原因是報價真的很難在參數傳遞。你需要使用eval:使用

if ! eval $test 
0

我想說檢查文本文件中字符串的方式是grep。

你的確切問題是什麼?

此外,您可以調整您的NFS裝載參數,以擺脫根本問題。同步可能也有幫助。請參閱NFS文檔。

+0

我無法更改安裝參數。我的腳本應該足夠強大來處理延遲。問題不在於grep本身,而在於grep測試沒有像我期望的那樣得到評估。 – 2009-07-03 07:10:51

0

如果您想在「if」中使用waitLoop,您可能需要將「exit」更改爲「return」,以便腳本的其餘部分可以處理錯誤情況(甚至沒有消息向用戶通知腳本死亡之前發生了什麼故障)。

另一個問題是使用「$ test」來保存一個命令意味着你在實際執行時沒有獲得shell擴展,只是評估。因此,如果您說test =「grep \」foo \「\」bar baz \「」,而不是在文件中用七個字符名稱bar baz查找三個字母字符串foo,它會查找五個char字符串在九個char文件「bar baz」中的「foo」。

所以,你可以決定你不需要外殼的魔法,並設置測試=「grep的-sq^sometext $ somefilename」,或者你可以讓外殼來處理的東西,如明確報價:

if /bin/sh -c "$test" 
then 
    ... 
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 

這東西是行不通的,但是,如果多個進程嘗試在同一時間訪問該文件。

0

我剛剛有完全相同的問題。我使用了類似的方法來處理OP中包含的超時等待事件;不過,我還包括一個文件大小的檢查。如果文件在上次檢查後增加了大小,我會重置超時定時器。我正在寫的文件可能只有幾個gig,所以他們需要一段時間才能跨NFS進行寫入。

對於您的特定情況,這可能是過度的,但我也有我的寫作過程計算文件的散列寫完後。我使用了md5,但是像crc32這樣的東西也可以工作。該散列從作者廣播到(多個)閱讀器,並且閱讀器等待,直到a)文件大小停止增加,以及b)文件的(新計算的)散列與作者發送的散列相匹配。

0

我們有類似的問題,但原因不同。我們正在讀取s文件,將其發送到SFTP服務器。運行腳本的機器不是SFTP服務器。

我所做的是在cron中設置它(儘管帶睡眠的循環也會起作用)來執行文件的cksum。當舊的cksum與當前的cksum匹配時(文件沒有改變確定的時間),我們知道寫入完成並傳輸文件。

爲了保證安全,我們從不在備份前覆蓋本地文件,只有當遠程文件中有兩個cksum匹配且cksum與本地文件不匹配時纔會傳輸。

如果你需要代碼示例,我相信我可以挖掘它們。

0

shell將您的謂詞分解爲單詞。抓住它所有[email protected]如下面的代碼:

#! /bin/bash 

waitFor() 
{ 
    local tries=$1 
    shift 
    local predicate="[email protected]" 

    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 

太糟糕了打字稿是不是看着它實時一樣有趣。

-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

假設你只希望從文件中讀取時沒有其他書面形式向它(即寫作過程已完成) - 你可以檢查是否沒有其他具有文件句柄呢?