2017-10-13 60 views
0

根據這個問題我敢不允許評論:變量擴展的Bash陷阱?

Is it necessary to specify traps other than EXIT?

恕我直言,這是一個不完整的答案,因爲它不包括通常的情況是:

TEMPDIR_OR_FILE=$(mktemp [ some switches and params and an XXX pattern]) 
# ...so we want trap to do rm -rf ${TEMPDIR_OR_FILE} 

給出的例子是:

# reset 
trap 'excode=$?; cmd; trap - EXIT; echo $excode' EXIT HUP INT QUIT PIPE TERM 

# ignore 
trap 'excode=$?; trap "" EXIT; cmd; echo $excode' EXIT HUP INT QUIT PIPE TERM 

這裏的問題是,單引號阻止你exp anding ${TEMPDIR_OR_FILE}

我認爲這是一個複雜因素是變量擴大的時間。我需要${TEMPDIR_OR_FILE}立即展開,但其他項目可能需要等待陷阱執行。我如何完成這項工作?

+0

由於旁邊所有大寫名稱用於具有對操作系統或系統有意義的變量,而具有至少一個小寫字符的名稱保留給應用程序使用,並且保證不會修改POSIX指定工具的行爲。請參閱http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html第四段。 –

+0

這就是說,**爲什麼要在陷阱被定義時擴展TEMPDIR_OR_FILE,而不是執行它時?稍後在執行時執行此操作(通過將定義放在外部單引號內)可以讓您更改正在使用的臨時文件。 –

+1

根據我的經驗,這不是一個問題。這些變量通常會設置一次,甚至可能只讀,然後用於程序的其餘部分。延期擴展不會改變任何內容。爲什麼你需要更快地解析它?我大概可以制定一個kludge,但不願意增加維護頭痛。 –

回答

1

最佳實踐:展開在執行時

簡單的例子

你擔心的代碼,

trap 'EXIT' 'rm -f "$TEMPDIR_OR_FILE"' 

... 確實工作;它只是在陷阱運行時查找TEMPDIR_OR_FILE,而不是當它被定義時。沒有什麼不妥:當陷阱運行的時候是查看臨時文件定義的時候,因爲這樣腳本的其餘部分可以在執行過程中適當地更改這些定義。

越來越多樣化:處理任意數量的臨時文件

考慮以下幾點:

declare -A tempfiles=() 
cleanup() { ((${#tempfiles[@]})) && rm -rf -- "${!tempfiles[@]}"; } 
trap 'cleanup' EXIT 

# ...do some stuff... 
tempfiles[something]=$(mktemp -t -d something.XXXXXX) 
echo "hello" >"${tempfiles[something]}/greeting" 

# ...do more stuff... 
tempfiles[something_else]=$(mktemp -t something_else.XXXXXX) 
if [[ $keep_something_else ]]; then 
    # the user wants us to keep this temporary file! remove it from deletion list 
    unset tempfiles[keep_something_else] 
fi 

通過上述,您定義的清理功能只是一次,並不需要知道你當時的臨時目錄;當您退出時,您會查看該列表,因爲它存在,然後


字面解釋:擴大在定義時

在大多數情況下,這是可取的執行陷阱時展開變量,VS時,它的定義。但是,您要求以其他方式進行操作。

爲此安全,使用printf %q來生成文件名的eval -safe版本,並定義陷阱時展開在雙引號。

printf -v tempdir_or_file_q '%q' "$TEMPDIR_OR_FILE" 
trap 'retval=$?; rm -rf '"${tempdir_or_file_q}"'; exit "$retval"' 

請注意,我們引用您想在定義時展開,展開它在雙引號,結束這些雙引號和切換回單引號後的變量之前結束最初的單引號。