2010-12-22 65 views
21

我有一個bash程序將寫入輸出文件。該文件可能存在也可能不存在,但該腳本必須檢查權限並提前失敗。我找不到一個優雅的方式來實現這一點。這是我的嘗試。Bash:創建一個文件,如果它不存在,否則檢查它是否可寫

 
set +e 
touch $file 
set -e 

if [ $? -ne 0 ]; then exit;fi 

我一直set -e對這個腳本,以便它失敗,如果有過任何線上的錯誤。有沒有更簡單的方法來執行上述腳本?

+1

我必須警告你,有一個競爭條件。您無法儘早檢查錯誤。在你檢查的時候文件可能已經存在了,但是在你開始寫入文件的時候已經被刪除了。或者更糟的是,權限改變了。我建議你打開文件寫入並獲取描述符。如果那個手術成功了,那你很好。在這種情況下,文件是否被刪除並不重要,操作系統會在刪除的情況下保持inode打開,並從文件名稱中「解除」它。 – 2010-12-23 13:26:48

+0

幫我理解。如果日誌文件在腳本運行時被刪除,那麼如果我打開描述符,嘗試寫入它就會成功?但該文件被刪除..數據去哪裏?我不希望它在這些罕見的情況下失敗嗎? – User1 2010-12-23 15:43:32

+1

如果文件被刪除(更具體地說,未鏈接),同時打開寫入,則文件保留在文件系統中,直到所有文件句柄關閉,無論是顯式還是退出進程。如果你的進程是寫入文件的唯一東西,它將繼續填滿磁盤,但不能被任何其他進程打開(因爲沒有目錄項)。 – Phil 2010-12-23 17:28:21

回答

20

,而不是在不同的線路檢查$?,立即檢查返回值是這樣的:

touch file || exit 

只要你umask不限制被設定寫入位,你可以依靠返回值touch

2

您可以使用-w來檢查文件是否可寫(在bash手冊頁中搜索它)。

if [[ ! -w $file ]]; then exit; fi 
2

打開文件進行寫入。在shell中,這是通過輸出重定向完成的。您可以重定向shell的標準輸出,方法是將內置的參數exec設置爲無參數。

set -e 
exec >shell.out # exit if shell.out can't be opened 
echo "This will appear in shell.out" 

確保您沒有設置noclobber選項(這是有用的交互,但往往無法使用的腳本)。如果要截斷文件(如果存在),則使用>;如果要附加,則使用>>

如果您只想測試權限,則可以運行: >foo.out來創建該文件(如果存在,則將其截斷)。

如果您只想要一些命令寫入文件,請在其他描述符上打開它,然後根據需要重定向。

set -e 
exec 3>foo.out 
echo "This will appear on the standard output" 
echo >&3 "This will appear in foo.out" 
echo "This will appear both on standard output and in foo.out" | tee /dev/fd/3 

/dev/fd不支持無處不在;它可至少在Linux,* BSD,Solaris和Cygwin的。)

30

爲什麼複雜的事情?

file=exists_and_writeable 

if [ ! -e "$file" ] ; then 
    touch "$file" 
fi 

if [ ! -w "$file" ] ; then 
    echo cannot write to $file 
    exit 1 
fi 

或者,更簡潔,

([ -e "$file" ] || touch "$file") && [ ! -w "$file" ] && echo cannot write to $file && exit 1 
3

爲什麼必須在腳本的早期失敗?通過分離可寫測試和文件open(),您可以引入競爭條件。相反,爲什麼不嘗試打開(截斷/追加)文件進行寫入,並處理錯誤?喜歡的東西:

$ echo foo > output.txt 
$ if [ $? -ne 0 ]; then die("Couldn't echo foo") 

正如其他人更不用說了,如果你想避免覆蓋現有文件「noclobber選項」選項可能是有用的。

相關問題