# 7.2 文件測試操作
下列每一個`test`選項在滿足條件時,返回0(真)。
### -e
檢測文件是否存在
### -a
檢測文件是否存在
等價于 `-e`。不推薦使用,已被棄用[^1]。
### -f
文件是常規文件(regular file),而非目錄或 [設備文件](http://tldp.org/LDP/abs/html/devref1.html#DEVFILEREF)
### -s
文件大小不為0
### -d
文件是一個目錄
### -b
文件是一個 [塊設備](http://tldp.org/LDP/abs/html/devref1.html#BLOCKDEVREF)
### -c
文件是一個 [字符設備](http://tldp.org/LDP/abs/html/devref1.html#CHARDEVREF)
```bash
device0="/dev/sda2" # / (根目錄)
if [ -b "$device0" ]
then
echo "$device0 is a block device."
fi
# /dev/sda2 是一個塊設備。
device1="/dev/ttyS1" # PCMCIA 調制解調卡
if [ -c "$device1" ]
then
echo "$device1 is a character device."
fi
# /dev/ttyS1 是一個字符設備。
```
### -p
文件是一個 [管道設備](http://tldp.org/LDP/abs/html/special-chars.html#PIPEREF)
```bash
function show_input_type()
{
[ -p /dev/fd/0 ] && echo PIPE || echo STDIN
}
show_input_type "Input" # STDIN
echo "Input" | show_input_type # PIPE
# 這個例子由 Carl Anderson 提供。
```
### -h
文件是一個 [符號鏈接](http://tldp.org/LDP/abs/html/basic.html#SYMLINKREF)
### -L
文件是一個符號鏈接
### -S
文件是一個 [套接字](http://tldp.org/LDP/abs/html/devref1.html#SOCKETREF)
### -t
文件([文件描述符](http://tldp.org/LDP/abs/html/io-redirection.html#FDREF))與終端設備關聯
該選項通常被用于 [測試](http://tldp.org/LDP/abs/html/intandnonint.html#II2TEST) 腳本中的 `stdin [ -t 0 ]` 或 `stdout [ -t 1 ]` 是否為終端設備。
### -r
該文件對執行測試的用戶可讀
### -w
該文件對執行測試的用戶可寫
### -x
該文件可被執行測試的用戶所執行
### -g
文件或目錄設置了 set-group-id `sgid` 標志
如果一個目錄設置了 `sgid` 標志,那么在該目錄中所有的新建文件的權限組都歸屬于該目錄的權限組,而非文件創建者的權限組。該標志對共享文件夾很有用。
### -u
文件設置了 set-user-id `suid` 標志。
一個屬于 root 的可執行文件設置了 `suid` 標志后,即使是一個普通用戶執行也擁有 root 權限[^2]。對需要訪問硬件設備的可執行文件(例如 `pppd` 和 `cdrecord`)很有用。如果沒有 `suid` 標志,這些可執行文件就不能被非 root 用戶所調用了。
```
-rwsr-xr-t 1 root 178236 Oct 2 2000 /usr/sbin/pppd
```
設置了 `suid` 標志后,在權限中會顯示 `s`。
### -k
設置了粘滯位(sticky bit)。
標志粘滯位是一種特殊的文件權限。如果文件設置了粘滯位,那么該文件將會被存儲在高速緩存中以便快速訪問[^3]。如果目錄設置了該標記,那么它將會對目錄的寫權限進行限制,目錄中只有文件的擁有者可以修改或刪除文件。設置標記后你可以在權限中看到 `t`。
```
drwxrwxrwt 7 root 1024 May 19 21:26 tmp/
```
如果一個用戶不是設置了粘滯位目錄的擁有者,但對該目錄有寫權限,那么他僅僅可以刪除目錄中他所擁有的文件。這可以防止用戶不經意間刪除或修改其他人的文件,例如 `/tmp` 文件夾。(當然目錄的所有者可以刪除或修改該目錄下的所有文件)
### -O
執行用戶是文件的擁有者
### -G
文件的組與執行用戶的組相同
### -N
文件在在上次訪問后被修改過了
### f1 -nt f2
文件 f1 比文件 f2 新
### f1 -ot f2
文件 f1 比文件 f2 舊
### f1 -ef f2
文件 f1 和文件 f2 硬鏈接到同一個文件
### !
取反——對測試結果取反(如果條件缺失則返回真)。
樣例 7-4. 檢測鏈接是否損壞
```bash
#!/bin/bash
# broken-link.sh
# Lee bigelow <ligelowbee@yahoo.com> 編寫。
# ABS Guide 經許可可以使用。
# 該腳本用來發現輸出損壞的鏈接。輸出的結果是被引用的,
#+ 所以可以直接導到 xargs 中進行處理 :)
# 例如:sh broken-link.sh /somedir /someotherdir|xargs rm
#
# 更加優雅的方式:
#
# find "somedir" -type 1 -print0|\
# xargs -r0 file|\
# grep "broken symbolic"|
# sed -e 's/^\|: *broken symbolic.*$/"/g'
#
# 但是這種方法不是純 Bash 寫法。
# 警告:小心 /proc 文件下的文件和任意循環鏈接!
############################################
# 如果不給腳本傳任何參數,那么 directories-to-search 設置為當前目錄
#+ 否則設置為傳進的參數
#####################
[ $# -eq 0 ] && directory=`pwd` || directory=$@
# 函數 linkchk 是用來檢測傳入的文件夾中是否包含損壞的鏈接文件,
#+ 并引用輸出他們。
# 如果文件夾中包含子文件夾,那么將子文件夾繼續傳給 linkchk 函數進行檢測。
#################
linkchk () {
for element in $1/*; do
[ -h "$element" -a ! -e "$element" ] && echo \"$element\"
[ -d "$element" ] && linkchk $element
# -h 用來檢測是否是鏈接,-d 用來檢測是否是文件夾。
done
}
# 檢測傳遞給 linkchk() 函數的參數是否是一個存在的文件夾,
#+ 如果不是則報錯。
################
for directory in $direcotrys; do
if [ -d $directory ]
then linkchk $directory
else
echo "$directory is not a directory"
echo "Usage $0 dir1 dir2 ..."
fi
done
exit $?
```
[樣例 31-1](http://tldp.org/LDP/abs/html/zeros.html#COOKIES),[樣例 11-8](http://tldp.org/LDP/abs/html/loops1.html#BINGREP),[樣例 11-3](http://tldp.org/LDP/abs/html/loops1.html#FILEINFO),[樣例 31-3](http://tldp.org/LDP/abs/html/zeros.html#RAMDISK)和[樣例 A-1](http://tldp.org/LDP/abs/html/contributed-scripts.html#MAILFORMAT) 也包含了文件測試操作符的使用。
[^1]: 摘自1913年版本的韋氏詞典<br><pre>Deprecate<br>...<br><br>To pray against, as an evil;<br>to seek to avert by prayer;<br>to desire the removal of;<br>to seek deliverance from;<br>to express deep regret for;<br>to disapprove of strongly.</pre>
[^2]: 注意使用 suid 的可執行文件可能會帶來安全問題。suid 標記對 shell 腳本沒有影響。
[^3]: 在 Linux 系統中,文件已經不使用粘滯位了, 粘滯位只作用于目錄。
- 第一部分 初見shell
- 1. 為什么使用shell編程
- 2. 和Sha-Bang(#!)一起出發
- 2.1 調用一個腳本
- 2.2 牛刀小試
- 第二部分 shell基礎
- 3. 特殊字符
- 4. 變量與參數
- 4.1 變量替換
- 4.2 變量賦值
- 4.3 Bash弱類型變量
- 4.4 特殊變量類型
- 5. 引用
- 5.1 引用變量
- 5.2 轉義
- 6. 退出與退出狀態
- 7. 測試
- 7.1 測試結構
- 7.2 文件測試操作
- 7.3 其他比較操作
- 7.4 嵌套 if/then 條件測試
- 7.5 牛刀小試
- 8. 運算符相關話題
- 8.1 運算符
- 8.2 數字常量
- 8.3 雙圓括號結構
- 8.4 運算符優先級
- 第三部分 shell進階
- 10. 變量處理
- 10.1 字符串處理
- 10.1.1 使用 awk 處理字符串
- 10.1.2 參考資料
- 10.2 參數替換
- 11. 循環與分支
- 11.1 循環
- 11.2 嵌套循環
- 11.3 循環控制
- 11.4 測試與分支
- 12. 命令替換
- 13. 算術擴展
- 14. 休息時間
- 第五部分 進階話題
- 19. 嵌入文檔
- 20. I/O 重定向
- 20.1 使用 exec
- 20.2 重定向代碼塊
- 20.3 應用程序
- 22. 限制模式的Shell
- 23. 進程替換
- 26. 列表結構
- 25. 別名