# 11.1 循環
循環是當循環控制條件為真時,一系列命令迭代[^1]執行的代碼塊。
### for 循環
### `for arg in [list]`
這是 shell 中最基本的循環結構,它與C語言形式的循環有著明顯的不同。
```bash
for arg in [list]
do
command(s)...
done
```
>  在循環的過程中,`arg` 會從 `list` 中連續獲得每一個變量的值。
>
```bash
for arg in "$var1" "$var2" "$var3" ... "$varN"
# 第一次循環中,arg = $var1
# 第二次循環中,arg = $var2
# 第三次循環中,arg = $var3
# ...
# 第 N 次循環中,arg = $varN
>
# 為了防止可能的字符分割問題,[list] 中的參數都需要被引用。
```
參數 list 中允許含有 [通配符](http://tldp.org/LDP/abs/html/special-chars.html#ASTERISKREF)。
如果 `do` 和 `for` 寫在同一行時,需要在 list 之后加上一個分號。
`for arg in [list] ; do`
樣例 11-1. 簡單的 for 循環
```bash
#!/bin/bash
# 列出太陽系的所有行星。
for planet in Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto
do
echo $planet # 每一行輸出一個行星。
done
echo; echo
for planet in "Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto"
# 所有的行星都輸出在一行上。
# 整個 'list' 被包裹在引號中時是作為一個單一的變量。
# 為什么?因為空格也是變量的一部分。
do
echo $planet
done
echo; echo "Whoops! Pluto is no longer a planet!"
exit 0
```
[list] 中的每一個元素中都可能含有多個參數。這在處理參數組中非常有用。在這種情況下,使用 [`set`](http://tldp.org/LDP/abs/html/internal.html#SETREF) 命令(查看 [樣例 15-16](http://tldp.org/LDP/abs/html/internal.html#EX34))強制解析 [list] 中的每一個元素,并將元素的每一個部分分配給位置參數。
樣例 11-2. `for` 循環 [list] 中的每一個變量有兩個參數的情況
```bash
#!/bin/bash
# 讓行星再躺次槍。
# 將每個行星與其到太陽的距離放在一起。
for planet in "Mercury 36" "Venus 67" "Earth 93" "Mars 142" "Jupiter 483"
do
set -- $planet # 解析變量 "planet"
#+ 并將其每個部分賦值給位置參數。
# "--" 防止一些極端情況,比如 $planet 為空或者以破折號開頭。
# 因為位置參數會被覆蓋掉,因此需要先保存原先的位置參數。
# 你可以使用數組來保存
# original_params=("$@")
echo "$1 $2,000,000 miles from the sum"
#-------兩個制表符---將后面的一系列 0 連到參數 $2 上。
done
# (感謝 S.C. 做出的額外注釋。)
exit 0
```
一個單一變量也可以成為 `for` 循環中的 [list]。
樣例 11-3. 文件信息:查看一個單一變量中含有的文件列表的文件信息
```bash
#!/bin/bash
# fileinfo.sh
FILES="/usr/sbin/accept
/usr/sbin/pwck
/usr/sbin/chroot
/usr/bin/fakefile
/sbin/badblocks
/sbin/ypbind" # 你可能會感興趣的一系列文件。
# 包含一個不存在的文件,/usr/bin/fakefile。
echo
for file in $FILES
do
if [ ! -e "$file" ] # 檢查文件是否存在。
then
echo "$file does not exist."; echo
continue # 繼續判斷下一個文件。
fi
ls -l $file | awk '{ print $8 " file size: " $5 }' # 輸出其中的兩個域。
whatis `basename $file` # 文件信息。
# 腳本正常運行需要注意提前設置好 whatis 的數據。
# 使用 root 權限運行 /usr/bin/makewhatis 可以完成。
echo
done
exit 0
```
`for` 循環中的 [list] 可以是一個參數。
樣例 11-4. 操作含有一系列文件的參數
```bash
#!/bin/bash
filename="*txt"
for file in $filename
do
echo "Contents of $file"
echo "---"
cat "$file"
echo
done
```
如果在匹配文件擴展名的 `for` 循環中的 [list] 含有通配符(* 和 ?),那么將會進行文件名擴展。
樣例 11-5. 在 `for` 循環中操作文件
```bash
#!/bin/bash
# list-glob.sh: 通過文件名擴展在 for 循環中產生 [list]。
# 通配 = 文件名擴展。
echo
for file in *
# ^ Bash 在檢測到通配表達式時,
#+ 會進行文件名擴展。
do
ls -l "$file" # 列出 $PWD(當前工作目錄)下的所有文件。
# 回憶一下,通配符 "*" 會匹配所有的文件名,
#+ 但是,在文件名擴展中,他將不會匹配以點開頭的文件。
# 如果沒有匹配到文件,那么它將會擴展為它自身。
# 為了防止出現這種情況,需要設置 nullglob 選項。
#+ (shopt -s nullglob)。
# 感謝 S.C.
done
echo; echo
for file in [jx]*
do
rm -f $file # 刪除當前目錄下所有以 "j" 或 "x" 開頭的文件。
echo "Removed file \"$file\"".
done
echo
exit 0
```
如果在 `for` 循環中省略 `in [list]` 部分,那么循環將會遍歷位置參數(`$@`)。[樣例 A-15](http://tldp.org/LDP/abs/html/contributed-scripts.html#PRIMES) 中使用到了這一點。也可以查看 [樣例 15-17](http://tldp.org/LDP/abs/html/internal.html#REVPOSPARAMS)。
樣例 11-6. 缺少 `in [list]` 的 `for` 循環
```bash
#!/bin/bash
# 嘗試在帶參數和不帶參數兩種情況下調用這個腳本,觀察發生了什么。
for a
do
echo -n "$a "
done
# 缺失 'in list' 的情況下,循環會遍歷 '$@'
#+(命令行參數列表,包括空格)。
echo
exit 0
```
可以在 `for` 循環中使用 [命令代換](http://tldp.org/LDP/abs/html/commandsub.html#COMMANDSUBREF) 生成 [list]。查看 [樣例 16-54](http://tldp.org/LDP/abs/html/extmisc.html#EX53),[樣例 11-11](http://tldp.org/LDP/abs/html/loops1.html#SYMLINKS) 和 [樣例 16-48](http://tldp.org/LDP/abs/html/mathc.html#BASE)。
樣例 11-7. 在 `for` 循環中使用命令代換生成 [list]
```bash
#!/bin/bash
# for-loopcmd.sh: 帶命令代換所生成 [list] 的 for 循環
NUMBERS="9 7 3 8 37.53"
for number in `echo $NUMBERS` # for number in 9 7 3 8 37.53
do
echo -n "$number "
done
echo
exit 0
```
下面是使用命令代換生成 [list] 的更加復雜的例子。
樣例 11-8. 一種替代 `grep` 搜索二進制文件的方法
```bash
#!/bin/bash
# bin-grep.sh: 在二進制文件中定位匹配的字符串。
# 一種替代 `grep` 搜索二進制文件的方法
# 與 "grep -a" 的效果類似
E_BADARGS=65
E_NOFILE=66
if [ $# -ne 2 ]
then
echo "Usage: `basename $0` search_string filename"
exit $E_BADARGS
fi
if [ ! -f "$2" ]
then
echo "File \"$2\" does not exist."
exit $E_NOFILE
fi
IFS=$'\012' # 按照 Anton Filippov 的意見應該是
# IFS="\n"
for word in $( strings "$2" | grep "$1" )
# "strings" 命令列出二進制文件中的所有字符串。
# 將結果通過管道輸出到 "grep" 中,檢查是不是匹配的字符串。
do
echo $word
done
# 就像 S.C. 指出的那樣,第 23-30 行可以換成下面的形式:
# strings "$2" | grep "$1" | tr -s "$IFS" '[\n*]'
# 嘗試運行腳本 "./bin-grep.sh mem /bin/ls"
exit 0
```
下面的例子同樣展示了如何使用命令代換生成 [list]。
樣例 11-9. 列出系統中的所有用戶
```bash
#!/bin/bash
# userlist.sh
PASSWORD_FILE=/etc/passwd
n=1 # 用戶數量
for name in $(awk 'BEGIN{fs=":"}{print $1}' < "$PASSWORD_FILE" )
# 分隔符 = : ^^^^^^
# 輸出第一個域 ^^^^^^^^
# 讀取密碼文件 /etc/passwd ^^^^^^^^^^^^^^^^^
do
echo "USER #$n = $name"
let "n += 1"
done
# USER #1 = root
# USER #2 = bin
# USER #3 = daemon
# ...
# USER #33 = bozo
exit $?
# 討論:
# -----
# 一個普通用戶是如何讀取 /etc/passwd 文件的?
# 提示:檢查 /etc/passwd 的文件權限。
# 這算不算是一個安全漏洞?為什么?
```
另外一個關于 [list] 的例子也來自于命令代換。
樣例 11-10. 檢查目錄中所有二進制文件的原作者
```bash
#!/bin/bash
# findstring.sh
# 在指定目錄的二進制文件中尋找指定的字符串。
directory=/usr/bin
fstring="Free Software Foundation" # 查看哪些文件來自于 FSF。
for file in $( find $directory -type f -name '*' | sort )
do
strings -f $file | grep "$fstring" | sed -e "s%$driectory%%"
# 在 "sed" 表達式中,你需要替換掉 "/" 分隔符,
#+ 因為 "/" 是一個會被過濾的字符。
# 如果不做替換,將會產生一個錯誤。(你可以嘗試一下。)
done
exit $?
# 簡單的練習:
# ----------
# 修改腳本,使其可以從命令行參數中獲取 $directory 和 $fstring。
```
最后一個關于 [list] 和命令代換的例子,但這個例子中的命令是一個[函數](http://tldp.org/LDP/abs/html/functions.html#FUNCTIONREF)。
```bash
generate_list ()
{
echo "one two three"
}
for word in $(generate_list) # "word" 獲得函數執行的結果。
do
echo "$word"
done
# one
# two
# three
```
`for` 循環的結果可以通過管道導向至一個或多個命令中。
樣例 11-11. 列出目錄中的所有符號鏈接。
```bash
#!/bin/bash
# symlinks.sh: 列出目錄中的所有符號鏈接。
directory=${1-`pwd`}
# 如果沒有特別指定,缺省目錄為當前工作目錄。
# 等價于下面的代碼塊。
# ---------------------------------------------------
# ARGS=1 # 只有一個命令行參數。
#
# if [ $# -ne "$ARGS" ] # 如果不是只有一個參數的情況下
# then
# directory=`pwd` # 設為當前工作目錄。
# else
# directory=$1
# fi
# ---------------------------------------------------
echo "symbolic links in directory \"$directory\""
for file in "$( find $directory -type 1 )" # -type 1 = 符號鏈接
do
echo "$file"
done | sort # 否則文件順序會是亂序。
# 嚴格的來說這里并不需要使用循環,
#+ 因為 "find" 命令的輸出結果已經被擴展成一個單一字符串了。
# 然而,為了方便大家理解,我們使用了循環的方式。
# Dominik 'Aeneas' Schnitzer 指出,
#+ 不引用 $( find $directory -type 1 ) 的話,
# 腳本將在文件名包含空格時阻塞。
exit 0
# --------------------------------------------------------
# Jean Helou 提供了另外一種方法:
echo "symbolic links in directory \"$directory\""
# 備份當前的內部字段分隔符。謹慎永遠沒有壞處。
OLDIFS=$IFS
IFS=:
for file in $(find $directory -type 1 -printf "%p$IFS")
do # ^^^^^^^^^^^^^^^^
echo "$file"
done|sort
# James "Mike" Conley 建議將 Helou 的代碼修改為:
OLDIFS=$IFS
IFS='' # 空的內部字段分隔符意味著將不會分隔任何字符串
for file in $( find $directory -type 1 )
do
echo $file
done | sort
# 上面的代碼可以在目錄名包含冒號(前一個允許包含空格)
#+ 的情況下仍舊正常工作。
```
只需要對上一個樣例做一些小小的改動,就可以把在標準輸出 `stdout` 中的循環 [重定向](http://tldp.org/LDP/abs/html/io-redirection.html#IOREDIRREF) 到文件中。
樣例 11-12. 將目錄中的所有符號鏈接保存到文件中。
```bash
#!/bin/bash
# symlinks.sh: 列出目錄中的所有符號鏈接。
OUTFILE=symlinks.list
directory=${1-`pwd`}
# 如果沒有特別指定,缺省目錄為當前工作目錄。
echo "symbolic links in directory \"$directory\"" > "$OUTFILE"
echo "---------------------------" >> "$OUTFILE"
for file in "$( find $directory -type 1 )" # -type 1 = 符號鏈接
do
echo "$file"
done | sort >> "$OUTFILE" # 將 stdout 的循環結果
# ^^^^^^^^^^^^^ 重定向到文件。
# echo "Output file = $OUTFILE"
exit $?
```
還有另外一種看起來非常像C語言中循環那樣的語法。你需要使用到 [雙圓括號](http://tldp.org/LDP/abs/html/dblparens.html#DBLPARENSREF) 語法。
樣例 11-13. C語言風格的循環
```bash
#!/bin/bash
# 用多種方式數到10。
echo
# 基礎版
for a in 1 2 3 4 5 6 7 8 9 10
do
echo -n "$a "
done
echo; echo
# +==========================================+
# 使用 "seq"
for a in `seq 10`
do
echo -n "$a "
done
echo; echo
# +==========================================+
# 使用大括號擴展語法
# Bash 3+ 版本有效。
for a in {1..10}
do
echo -n "$a "
done
echo; echo
# +==========================================+
# 現在用類似C語言的語法再實現一次。
LIMIT=10
for ((a=1; a <= LIMIT ; a++)) # 雙圓括號語法,不帶 $ 的 LIMIT
do
echo -n "$a "
done # 從 ksh93 中學習到的特性。
echo; echo
# +==========================================+
# 我們現在使用C語言中的逗號運算符來使得兩個變量同時增加。
for ((a=1, b=1; a <= LIMIT ; a++, b++))
do # 逗號連接操作。
echo -n "$a-$b "
done
echo; echo
exit 0
```
還可以查看 [樣例 27-16](http://tldp.org/LDP/abs/html/arrays.html#QFUNCTION),[樣例 27-17](http://tldp.org/LDP/abs/html/arrays.html#TWODIM) 和 [樣例 A-6](http://tldp.org/LDP/abs/html/contributed-scripts.html#COLLATZ)。
\---
接下來,我們將展示在真實環境中應用的循環。
樣例 11-14. 在批處理模式下使用 `efax`
```bash
#!/bin/bash
# 傳真(必須提前安裝了 'efax' 模塊)。
EXPECTED_ARGS=2
E_BADARGS=85
MODEM_PORT="/dev/ttyS2" # 你的電腦可能會不一樣。
# ^^^^^ PCMCIA 調制解調卡缺省端口。
if [ $# -ne $EXPECTED_ARGS ]
# 檢查是不是傳入了適當數量的命令行參數。
then
echo "Usage: `basename $0` phone# text-file"
exit $E_BADARGS
fi
if [ ! -f "$2" ]
then
echo "File $2 is not a text file."
# File 不是一個正常文件或者文件不存在。
exit $E_BADARGS
fi
fax make $2 # 根據文本文件創建傳真格式文件。
for file in $(ls $2.0*) # 連接轉換后的文件。
# 在參數列表中使用通配符(文件名通配)。
do
fil="$fil $file"
done
efax -d "$MODEM_PORT" -t "T$1" $fil # 最后使用 efax。
# 如果上面一行執行失敗,嘗試添加 -o1。
# S.C. 指出,上面的 for 循環可以被壓縮為
# efax -d /dev/ttyS2 -o1 -t "T$1" $2.0*
#+ 但是這并不是一個好主意。
exit $? # efax 同時也會將診斷信息傳遞給標準輸出。
```
>  [關鍵字](http://tldp.org/LDP/abs/html/internal.html#KEYWORDREF) `do` 和 `done` 圈定了 for 循環代碼塊的范圍。但是在一些特殊的情況下,也可以被 [大括號](http://tldp.org/LDP/abs/html/special-chars.html#CODEBLOCKREF) 取代。
>
```bash
for((n=1; n<=10; n++))
# 沒有 do!
{
echo -n "* $n *"
}
# 沒有 done!
>
>
# 輸出:
# * 1 ** 2 ** 3 ** 4 ** 5 ** 6 ** 7 ** 8 ** 9 ** 10 *
# 并且 echo $? 返回 0,因此 Bash 并不認為這是一個錯誤。
>
>
echo
>
>
# 但是注意在典型的 for 循環 for n in [list] ... 中,
#+ 需要在結尾加一個分號。
>
for n in 1 2 3
{ echo -n "$n "; }
# ^
>
>
# 感謝 Yongye 指出這一點。
```
### while 循環
`while` 循環結構會在循環頂部檢測循環條件,若循環條件為真( [退出狀態](http://tldp.org/LDP/abs/html/exit-status.html#EXITSTATUSREF) 為0)則循環持續進行。與 [`for` 循環](http://tldp.org/LDP/abs/html/loops1.html#FORLOOPREF1) 不同的是,`while` 循環是在不知道循環次數的情況下使用的。
```bash
while [ condition ]
do
command(s)...
done
```
在 `while` 循環結構中,你不僅可以使用像 `if/test` 中那樣的 [括號結構](http://tldp.org/LDP/abs/html/testconstructs.html#TESTCONSTRUCTS1),也可以使用用途更廣泛的 [雙括號結構](http://tldp.org/LDP/abs/html/testconstructs.html#DBLBRACKETS)(`while [[ condition ]]`)。
就像在 `for` 循環中那樣,將 `do` 和循環條件放在同一行時需要加一個分號。
`while [ condition ] ; do`
在 `while` 循環中,括號結構 [并不是必須存在的](http://tldp.org/LDP/abs/html/loops1.html#WHILENOBRACKETS)。比如說 [`getopts` 結構](http://tldp.org/LDP/abs/html/internal.html#GETOPTSX)。
樣例 11-15. 簡單的 `while` 循環
```bash
#!/bin/bash
var0=0
LIMIT=10
while [ "$var0" -lt "$LIMIT" ]
# ^ ^
# 必須有空格,因為這是測試結構
do
echo -n "$var0 " # -n 不會另起一行
# ^ 空格用來分開輸出的數字。
var0=`expr $var0 + 1` # var0=$(($var0+1)) 效果相同。
# var0=$((var0 + 1)) 效果相同。
# let "var0 += 1" 效果相同。
done # 還有許多其他的方法也可以達到相同的效果。
echo
exit 0
```
樣例 11-16. 另一個例子
```bash
#!/bin/bash
echo
# 等價于:
while [ "$var1" != "end" ] # while test "$var1" != "end"
do
echo "Input variable #1 (end to exit) "
read var1 # 不是 'read $var1' (為什么?)。
echo "variable #1 = $var1" # 因為存在 "#",所以需要使用引號。
# 如果輸入的是 "end",也將會在這里輸出。
# 在結束本輪循環之前都不會再測試循環條件了。
echo
done
exit 0
```
一個 `while` 循環可以有多個測試條件,但只有最后的那一個條件決定了循環是否終止。這是一種你需要注意到的不同于其他循環的語法。
樣例 11-17. 多條件 `while` 循環
```bash
#!/bin/bash
var1=unset
previous=$var1
while echo "previous-variable = $previous"
echo
previous=$var1
[ "$var1" != end ] # 記錄下 $var1 之前的值。
# 在 while 循環中有4個條件,但只有最后的那個控制循環。
# 最后一個條件的退出狀態才會被記錄。
do
echo "Input variable #1 (end to exit) "
read var1
echo "variable #1 = $var1"
done
# 猜猜這是怎樣實現的。
# 這是一個很小的技巧。
exit 0
```
就像 `for` 循環一樣, `while` 循環也可以使用雙圓括號結構寫得像C語言那樣(也可以查看[樣例 8-5](http://tldp.org/LDP/abs/html/dblparens.html#CVARS))。
樣例 11-18. C語言風格的 `while` 循環
```bash
#!/bin/bash
# wh-loopc.sh: 在 "while" 循環中計數到10。
LIMIT=10 # 循環10次。
a=1
while [ "$a" -le $LIMIT ]
do
echo -n "$a "
let "a+=1"
done # 沒什么好奇怪的吧。
echo; echo
# +==============================================+
# 現在我們用C語言風格再寫一次。
((a = 1)) # a=1
# 雙圓括號結構允許像C語言一樣在賦值語句中使用空格。
while (( a <= LIMIT )) # 雙圓括號結構,
do #+ 并且沒有使用 "$"。
echo -n "$a "
((a += 1)) # let "a+=1"
# 是的,就是這樣。
# 雙圓括號結構允許像C語言一樣自增一個變量。
done
echo
# 這可以讓C和Java程序猿感覺更加舒服。
exit 0
```
在測試部分,`while` 循環可以調用 [函數](http://tldp.org/LDP/abs/html/functions.html#FUNCTIONREF)。
```bash
t=0
condition ()
{
((t++))
if [ $t -lt 5 ]
then
return 0 # true 真
else
return 1 # false 假
fi
}
while condition
# ^^^^^^^^^
# 調用函數循環四次。
do
echo "Still going: t = $t"
done
# Still going: t = 1
# Still going: t = 2
# Still going: t = 3
# Still going: t = 4
```
> 和 [if 測試](http://tldp.org/LDP/abs/html/testconstructs.html#IFGREPREF) 結構一樣,`while` 循環也可以省略括號。
>
```bash
while condition
do
command(s) ...
done
```
在 `while` 循環中結合 [`read`](http://tldp.org/LDP/abs/html/internal.html#READREF) 命令,我們就得到了一個非常易于使用的 [`while read`](http://tldp.org/LDP/abs/html/internal.html#WHILEREADREF) 結構。它可以用來讀取和解析文件。
```bash
cat $filename | # 從文件獲得輸入。
while read line # 只要還有可以讀入的行,循環就繼續。
do
...
done
# ==================== 摘自樣例腳本 "sd.sh" =================== #
while read value # 一次讀入一個數據。
do
rt=$(echo "scale=$SC; $rt + $value" | bc)
(( ct++ ))
done
am=$(echo "scale=$SC; $rt / $ct" | bc)
echo $am; return $ct # 這個功能“返回”了2個值。
# 注意:這個技巧在 $ct > 255 的情況下會失效。
# 如果要操作更大的數字,注釋掉上面的 "return $ct" 就可以了。
} <"$datafile" # 傳入數據文件。
```
>  在 `while` 循環后面可以通過 < 將標準輸入 [重定位到文件](http://tldp.org/LDP/abs/html/redircb.html#REDIRREF) 中。
> `while` 循環同樣可以 [通過管道](http://tldp.org/LDP/abs/html/internal.html#READPIPEREF) 傳入標準輸入中。
### until
與 `while` 循環相反,`until` 循環測試其頂部的循環條件,直到其中的條件為真時停止。
```bash
until [ condition-is-true ]
do
commands(s)...
done
```
注意到,跟其他的一些編程語言不同,`until` 循環的測試條件在循環頂部。
就像在 `for` 循環中那樣,將 `do` 和循環條件放在同一行時需要加一個分號。
`until[ condition-is-true ] ; do`
樣例 11-19. `until` 循環
```bash
#!/bin/bash
END_CONDITION=end
until [ "$var1" = "$END_CONDITION" ]
# 在循環頂部測試條件。
do
echo "Input variable #1 "
echo "($END_CONDITION to exit)"
read var1
echo "variable #1 = $var1"
echo
done
# --- #
# 就像 "for" 和 "while" 循環一樣,
#+ "until" 循環也可以寫的像C語言一樣。
LIMIT=10
var=0
until (( var > LIMIT ))
do # ^^ ^ ^ ^^ 沒有方括號,沒有 $ 前綴。
echo -n "$var "
(( var++ ))
done # 0 1 2 3 4 5 6 7 8 9 10
exit 0
```
如何在 `for`,`while` 和 `until` 之間做出選擇?我們知道在C語言中,在已知循環次數的情況下更加傾向于使用 `for` 循環。但是在Bash中情況可能更加復雜一些。Bash中的 `for` 循環相比起其他語言來說,結構更加松散,使用更加靈活。因此使用你認為最簡單的就好。
[^1]: 迭代:重復執行一個或一組命令。通常情況下,會使用`while`或者`until`進行控制。
- 第一部分 初見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. 別名