2008-12-04 30 views
0

我試圖編寫一個(sh -bourne shell)腳本,它們在寫入文件時處理行。我試圖通過將tail -f的輸出提供給while read循環來完成此操作。基於我在Google中的研究以及處理類似問題的this question,這種策略似乎是正確的,但使用bash。突破HP-UX中「while read」循環讀取的「tail -f」

從我讀過的文字看來,我應該能夠在跟隨的文件不存在時跳出循環。它沒有。事實上,似乎我能擺脫這種情況的唯一方法就是在另一個會話中殺死進程。 tail似乎要被罰款,否則工作作爲檢驗本:

 
touch file 
tail -f file | while read line 
do 
    echo $line 
done 

數據我追加到file在另一個會話似乎剛剛從上面寫的循環處理文件。

這是在HP-UX B.11.23上的版本。

感謝您提供任何幫助/見解!

回答

0

我不知道HP-UX tail但GNU tail--follow=name選項,將遵循文件名的文件(通過重新打開文件每隔幾秒鐘,而不是從它不會檢測到相同的文件描述符閱讀如果該文件是未鏈接),並且將退出時用來打開文件的文件名未鏈接:

tail --follow=name test.txt 
+0

嗨羅伯特。我在Google搜索中看到了這個選項,聽起來像是最好的選擇。遺憾的是,HP-UX不支持此選項。 – AgentConundrum 2008-12-04 04:39:55

+0

@代理 - 你可以下載和編譯(端口)GNU尾巴?它當然似乎是你想要的。 – tvanfosson 2008-12-04 04:47:36

1

如果你想打出來,當你的文件不存在了,只是做:

test -f file || break 

Placin g在你的循環中,應該爆發。

剩下的問題是,如何中斷讀取行,因爲這是阻塞。

這可以通過應用超時來完成,如讀取-t 5行。然後每5秒讀取一次,如果文件不再存在,則循環會中斷。注意:創建可以處理大小寫的循環,即讀取超時,但文件仍然存在。

編輯:似乎與超時read返回假的,所以你可以測試與超時相結合,其結果必然是:

tail -f test.file | while read -t 3 line || test -f test.file; do 
      some stuff with $line 
    done 
0

除非你使用GNU ,也沒辦法在跟蹤文件時它會自行終止。 -f選項實際上僅用於交互式監視 - 實際上,我有一本書說,-f「不可能在shell腳本中使用」。

但是對於問題的解決方案,我不完全確定這不是一個過度設計的方法,但我想你可以發送尾部到一個FIFO,然後有一個函數或腳本檢查文件是否存在,如果它沒有鏈接,就會將尾巴殺死。

 
#!/bin/sh 

sentinel() 
{ 
    while true 
    do 
     if [ ! -e $1 ] 
     then 
      kill $2 
      rm /tmp/$1 
      break 
     fi 
    done 
}  

touch $1 

mkfifo /tmp/$1 

tail -f $1 >/tmp/$1 & 

sentinel $1 $! & 

cat /tmp/$1 | while read line 
do 
    echo $line 
done 

做了一些天真的測試,它似乎工作還好,並沒有留下任何垃圾亂丟。

0

我從來沒有滿意這個答案,但我還沒有找到一種替代或者:

kill $(ps -o pid,cmd --no-headers --ppid $$ | grep tail | awk '{print $1}') 

獲取是當前進程的所有子進程,尋找尾巴,打印出的第一列(尾巴的pid),並殺死它。確實有罪惡 - 醜陋,這就是生活。

0

以下方法背景的tail -f file命令,回聲其進程id加上一個自定義串前綴(這裏tailpid:)到while迴路,其中與自定義串前綴行觸發另一個(背景執行)while循環,每5秒檢查是否file仍然存在。如果不是,tail -f file會被殺死,並且退出包含後臺循環while循環的子shell。

# cf. "The Heirloom Bourne Shell", 
# http://heirloom.sourceforge.net/sh.html, 
# http://sourceforge.net/projects/heirloom/files/heirloom-sh/ and 
# http://freecode.com/projects/bournesh 

/usr/local/bin/bournesh -c ' 
touch file 
(tail -f file & echo "tailpid: ${!}") | while IFS="" read -r line 
do 
    case "$line" in 
     tailpid:*) while sleep 5; do 
         #echo hello; 
         if [ ! -f file ]; then 
          IFS=" "; set -- ${line} 
          kill -HUP "$2" 
          exit 
         fi 
       done & 
       continue ;; 
    esac 
    echo "$line" 
done 
echo exiting ... 
'