2015-06-19 48 views
3

我很新的殼在Linux上,在我的Linux實例,我重定向程序的兩個文件的輸出和錯誤使用以下方式編程,並在後臺Linux中的IO重定向Bash shell腳本不重新創建移動/刪除的文件?

myprog > run.log 2>> err.log & 

這正常運行它,我得到我想要的行爲

現在有一個又一個後臺進程監視RUN.LOG和err.log,並將它們移動到其他文件名,如果日誌文件增長超過一定的閾值。

例如mv err.log err[date-time].log

我的期望是,在這個文件移動發生後,err.log將被myprog輸出重定向再次創建,並且新的輸出將被寫入該新文件。但是,在我的日誌文件監視過程移動文件後,err.log或run.log永遠不會再次創建,儘管myprog繼續運行時沒有任何問題。

這是Linux中的正常行爲嗎?如果是這樣,我該怎麼做才能讓我的預期行爲起作用?

+0

文件句柄綁定到inode,而不是文件名。文件系統上的哪個名稱(如果有)與inode鏈接的更改是完全透明的。這是非常理想的行爲 - 這就是爲什麼,例如,您可以在該軟件正在使用時在類UNIX操作系統上升級軟件包。 –

回答

4

是的。除非您第一次程序重新打開文件,否則即使您再也無法訪問它,它仍會繼續寫入舊文件。事實上,被刪除文件所使用的空間只有在每個進程關閉後纔可用。如果重新打開它是不可能的(即不能更改可執行文件或重新啓動它),那麼像http://httpd.apache.org/docs/2.4/programs/rotatelogs.html這樣的解決方案是最好的選擇。 它可以根據文件大小或時間旋轉日誌,甚至可以在旋轉後調用自定義腳本。

實例:

myprog | rotatelogs logname.log 50M 

這樣每當大小達到50兆字節的日誌將被旋轉。

[編輯:指出rotatelogs的較新版本]

+0

這沒有錯,但我認爲它不完整 - 沒有提供任何關於如何在不重新啓動腳本的情況下重新啓動shell腳本日誌記錄的提示。像'logrotate'這樣的''rotatelogs''會爲你做旋轉,但你仍然需要發信號通知使用一個新的目標文件。 –

+0

它不需要信號,這就是我說「如果重新打開它不可能(即不能更改可執行文件或重新啓動它)」的原因,「。實際使用情況爲「myprog | rotatelogs 」。這樣,它就會執行輪轉並重新打開文件。 – Vitor

+0

啊。在這種使用模式下具有完美意義。 –

0

如果我猜的話,它實際上是與一個文件描述符,而不是文件名登錄過程相關聯。當你重命名它時,你只能改變文件名。所以這個過程只是記錄到文件。只是一個猜測。如果我的任務是修復它,我會停止日誌記錄過程,並在此時重新啓動它,以將其重新關聯到正確的文件。

只是一個猜測。

+0

你是絕對正確的。我只是注意到,行爲正是你在這裏解釋的。在mv命令之後,我的文件仍然在不斷增長。現在我知道了這種行爲,我將能夠想出一個可能涉及文件複製(cp)的解決方案,而不是移動並截斷原始文件。 – user1824801

+1

@ user1824801,使用'cp'將打開你的競爭條件。移動原始文件,然後使用信號處理程序來觸發日誌目標的重新打開實際上是如何使用Apache和其他專業使用的軟件完成的。 –

+0

是的,謝謝@Charles Duffy。我意識到cp和truncate會導致競爭條件,如果myprog勝過我的日誌監視器,我將在這個過程中丟失一些日誌語句。 – user1824801

0

軟件與日誌輪換支持實際上已經寫在這個旋轉的支持。如果你看一下man logrotate,你會發現,一個典型的配置是這樣的:

"/var/log/httpd/access.log" /var/log/httpd/error.log { 
     rotate 5 
     mail [email protected] 
     size 100k 
     sharedscripts 
     postrotate 
      /usr/bin/killall -HUP httpd 
     endscript 
    } 

...這是說,它發送一個HUP信號,其日誌已被旋轉的程序;該程序的信號處理程序重新打開其輸出文件。


你可以在你的shell腳本就此別過:

reopen_logs() { 
    exec >>run.log 2>>err.log 
} 
trap reopen_logs HUP 

...然後,在旋轉日誌後,運行kill -HUP pid_of_yourscript;在下一次腳本本身執行命令時(因爲信號處理程序僅在預先執行的可執行文件之間運行),它將重新打開其輸出以重新創建日誌文件而無需重新啓動。