介紹各種在 Bash 指令稿中判斷檔案或目錄是否存在的方法與技巧,並提供實用範例。
在 Bash 中可以使用 test
指令搭配 -f
參數來檢查指定的檔案是否存在:
# 要檢查的檔案 FILE=/etc/resolv.conf # 使用 test 檢查檔案是否存在 if test -f "$FILE"; then echo "$FILE 檔案存在" else echo "$FILE 檔案不存在" fi
/etc/resolv.conf 檔案存在
test
指令還有另外一種中括號的寫法,這種寫法適用於所有符合 POSIX 標準的 shell,如果想要讓指令稿具有較高的可移植姓,就要採用這種寫法:
# 使用 [ 檢查檔案是否存在 if [ -f "$FILE" ]; then echo "$FILE 檔案存在" else echo "$FILE 檔案不存在" fi
除了單中括號之外,還有另外一種新式的雙中括號的寫法,這種寫法改善了單中括號的缺點(例如可以省略引號),但是只適用於較新的 shell(例如 Bash、Zsh 與 Ksh):
# 使用 [[ 檢查檔案是否存在 if [[ -f $FILE ]]; then echo "$FILE 檔案存在" else echo "$FILE 檔案不存在" fi
如果我們只是要在某個檔案存在時執行某個指令,可以改用以下這種簡略寫法,只有在指定檔案存在時才會執行 &&
之後的指令:
# 當檔案存在時,才執行指令(test 指令寫法) test -f "$FILE" && echo "$FILE 檔案存在" # 當檔案存在時,才執行指令(單中括號寫法) [ -f "$FILE" ] && echo "$FILE 檔案存在" # 當檔案存在時,才執行指令(雙中括號寫法) [[ -f $FILE ]] && echo "$FILE 檔案存在"
若要執行多行指令,可以將多行指令用大括號包起來,並以分號(;
)或 &&
分隔:
# 當檔案存在時,才執行指定的多行指令 [ -f "$FILE" ] && { echo "$FILE 檔案存在"; cp "$FILE" /tmp/; }
若要使用簡略寫法依據檔案是否存在執行不同指令,可以這樣寫:
# 依據檔案是否存在執行不同指令 [ -f "$FILE" ] && echo "$FILE 檔案存在" || echo "$FILE 檔案不存在"
若要檢查指定目錄是否存在,可以使用 test
指令搭配 -d
參數:
# 要檢查的目錄 DIR=/var/log # 檢查目錄是否存在 if [ -d "$DIR" ]; then echo "$DIR 目錄存在" else echo "$DIR 目錄不存在" fi
使用 &&
的簡略寫法:
# 當目錄存在時,才執行指令 [ -d "$DIR" ] && echo "$DIR 目錄存在"
這裡只示範中括號的寫法,另外兩種寫法以此類推。
test
的 -f
參數適用於檔案,而 -d
參數適用於目錄,若不想區分檔案或目錄,只檢查存在與否,可以改用 -e
參數。
# 要檢查的檔案或目錄 PATH=/var/log/nginx # 檢查檔案或目錄是否存在 if [ -e "$PATH" ]; then echo "$PATH 檔案或目錄存在" else echo "$PATH 檔案或目錄不存在" fi
如果只需要對檔案不存在的狀況進行處理,可以用這樣的寫法:
# 要檢查的檔案 FILE=/etc/not.exist # 使用 test 檢查檔案是否不存在 if ! test -f "$FILE"; then echo "$FILE 檔案不存在" fi # 使用 [ 檢查檔案是否不存在 if [ ! -f "$FILE" ]; then echo "$FILE 檔案不存在" fi # 使用 [[ 檢查檔案是否不存在 if [[ ! -f $FILE ]]; then echo "$FILE 檔案不存在" fi
以簡略寫法檢查檔案是否不存在:
# 當檔案不存在時,才執行指令(test 指令寫法) test -f "$FILE" || echo "$FILE 檔案不存在" # 當檔案不存在時,才執行指令(單中括號寫法) [ -f "$FILE" ] || echo "$FILE 檔案不存在" # 當檔案不存在時,才執行指令(雙中括號寫法) [[ -f $FILE ]] || echo "$FILE 檔案不存在"
若要一次檢查多個檔案是否都存在,可以搭配 -a
參數(代表 AND 運算):
# 要檢查的檔案 FILE1=/etc/resolv.conf FILE2=/etc/fstab # 使用 test 檢查兩個檔案是否皆存在 if test -f "$FILE1" -a -f "$FILE2"; then echo "$FILE1 與 $FILE2 檔案皆存在" fi # 使用 [ 檢查兩個檔案是否皆存在 if [ -f "$FILE1" -a -f "$FILE2" ]; then echo "$FILE1 與 $FILE2 檔案皆存在" fi
如果要檢查至少一個檔案存在的狀況,可以搭配 -o
參數(代表 OR 運算):
# 使用 test 檢查是否至少存在一個檔案 if test -f "$FILE1" -o -f "$FILE2"; then echo "$FILE1 與 $FILE2 至少其中一個檔案存在" fi # 使用 [ 檢查是否至少存在一個檔案 if [ -f "$FILE1" -o -f "$FILE2" ]; then echo "$FILE1 與 $FILE2 至少其中一個檔案存在" fi
另外一種寫法是使用 shell 中的 &&
與 ||
運算子:
# 使用 [ 檢查兩個檔案是否皆存在 if [ -f "$FILE1" ] && [ -f "$FILE2" ]; then echo "$FILE1 與 $FILE2 檔案皆存在" fi # 使用 [ 檢查是否至少存在一個檔案 if [ -f "$FILE1" ] || [ -f "$FILE2" ]; then echo "$FILE1 與 $FILE2 至少其中一個檔案存在" fi
以下是一個完整的指令稿範例,它會從參數讀取檔案名稱,逐一檢查每個路徑是否存在,並判斷是檔案還是目錄。
#!/bin/bash # 從參數列讀取路徑 for PATH in ${@}; do # 檢查路徑是檔案或目錄 if [ -f "$PATH" ]; then echo "$PATH 檔案存在" elif [ -d "$PATH" ]; then echo "$PATH 目錄存在" else echo "$PATH 檔案或目錄不存在" fi done
將這段指令稿儲存為 check_path.sh
後,即可用來檢查檔案或目錄:
# 檢查各路徑是檔案或目錄
./check_path.sh /etc/resolv.conf /var/log /not/exist
/etc/resolv.conf 檔案存在 /var/log 目錄存在 /not/exist 檔案或目錄不存在
參考資料:Linuxize、devconnected