有時,Bash 腳本需要創建臨時文件或臨時目錄。
常見的做法是,自己在/tmp目錄裡面生成一個文件,這樣做有很多弊端。本文介紹如何安全地處理臨時文件。

一、臨時文件的安全問題
直接創建臨時文件,尤其在/tmp目錄裡面,往往會導致安全問題。
首先,/tmp目錄是所有人可讀寫的,任何用戶都可以往該目錄裡面寫文件。創建的臨時文件也是所有人可讀的。
$ touch /tmp/info.txt $ ls -l /tmp/info.txt -rw-r--r-- 1 ruanyf ruanyf 0 12月 28 17:12 /tmp/info.txt
上面命令在/tmp目錄直接創建文件,該文件默認是所有人可讀的。
其次,如果攻擊者知道臨時文件的文件名,他可以創建符號鏈接,鏈接到臨時文件,可能導致系統運行異常。攻擊者也可能向腳本提供一些惡意數據。因此,臨時文件最好使用不可預測、每次都不一樣的文件名。
最後,臨時文件使用完畢,應該刪除。但是,腳本意外退出時,往往會忽略清理臨時文件。
二、臨時文件的最佳實踐
腳本生成臨時文件,應該遵循下面的規則。
- 創建前檢查文件是否已經存在。
- 確保臨時文件已成功創建。
- 臨時文件必須有權限的限制。
- 臨時文件要使用不可預測的文件名。
- 腳本退出時,要刪除臨時文件(使用
trap命令)。
三、mktemp 命令的用法
mktemp命令就是為安全創建臨時文件而設計的。雖然在創建臨時文件之前,它不會檢查臨時文件是否存在,但是它支持唯一文件名和清除機制,因此可以減輕安全攻擊的風險。
直接運行mktemp命令,就能生成一個臨時文件。
$ mktemp /tmp/tmp.4GcsWSG4vj $ ls -l /tmp/tmp.4GcsWSG4vj -rw------- 1 ruanyf ruanyf 0 12月 28 12:49 /tmp/tmp.4GcsWSG4vj
上面命令中,mktemp命令生成的臨時文件名是隨機的,而且權限是隻有用戶本人可讀寫。
Bash 腳本使用mktemp命令的用法如下。
#!/bin/bash TMPFILE=$(mktemp) echo "Our temp file is $TMPFILE"
為了確保臨時文件創建成功,mktemp命令後面最好使用 OR 運算符(||),指定創建失敗時退出腳本。
#!/bin/bash TMPFILE=$(mktemp) || exit 1 echo "Our temp file is $TMPFILE"
為了保證腳本退出時臨時文件被刪除,可以使用trap命令指定退出時的清除操作(詳見後文)。
#!/bin/bash trap 'rm -f "$TMPFILE"' EXIT TMPFILE=$(mktemp) || exit 1 echo "Our temp file is $TMPFILE"
四、mktemp 命令的參數
-d參數可以創建一個臨時目錄。
$ mktemp -d /tmp/tmp.Wcau5UjmN6
-p參數可以指定臨時文件所在的目錄。默認是使用$TMPDIR環境變量指定的目錄,如果這個變量沒設置,那麼使用/tmp目錄。
$ mktemp -p /home/ruanyf/ /home/ruanyf/tmp.FOKEtvs2H3
-t參數可以指定臨時文件的文件名模板,模板的末尾必須至少包含三個連續的X字符,表示隨機字符,建議至少使用六個X。默認的文件名模板是tmp.後接十個隨機字符。
$ mktemp -t mytemp.XXXXXXX /tmp/mytemp.yZ1HgZV
五、trap 命令的用法
trap命令用來在 Bash 腳本中響應系統信號。
最常見的系統信號就是 SIGINT(中斷),即按 Ctrl + C 所產生的信號。trap命令的-l參數,可以列出所有的系統信號。
$ trap -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT ... ...
trap的命令格式如下。
$ trap [動作] [信號]
上面代碼中,"動作"是一個 Bash 命令,"信號"常用的有以下幾個。
- HUP:編號1,腳本與所在的終端脫離聯繫。
- INT:編號2,用戶按下 Ctrl + C,意圖讓腳本中止運行。
- QUIT:編號3,用戶按下 Ctrl + 斜槓,意圖退出腳本。
- KILL:編號9,該信號用於殺死進程。
- TERM:編號15,這是
kill命令發出的默認信號。- EXIT:編號0,這不是系統信號,而是 Bash 腳本特有的信號,不管什麼情況,只要退出腳本就會產生。
trap命令響應EXIT信號的寫法如下。
$ trap 'rm -f "$TMPFILE"' EXIT
上面命令中,腳本遇到EXIT信號時,就會執行rm -f "$TMPFILE"。
trap 命令的常見使用場景,就是在 Bash 腳本中指定退出時執行的清理命令。
#!/bin/bash trap 'rm -f "$TMPFILE"' EXIT TMPFILE=$(mktemp) || exit 1 ls /etc > $TMPFILE if grep -qi "kernel" $TMPFILE; then echo 'find' fi
上面代碼中,不管是腳本正常執行結束,還是用戶按 Ctrl + C 終止,都會產生EXIT信號,從而觸發刪除臨時文件。
注意,trap命令必須放在腳本的開頭。否則,它上方的任何命令導致腳本退出,都不會被它捕獲。
如果trap需要觸發多條命令,可以封裝一個 Bash 函數。
function egress { command1 command2 command3 } trap egress EXIT
六、參考鏈接
- Working with Temporary Files and Directories in Shell Scripts, Steven Vona
- Using Trap to Exit Bash Scripts Cleanly, Steven Vona
- Sending and Trapping Signals
(完)












