一. 創建互動式腳本 使用 echo命令的選項 關於各種命令的使用,可以使用 來查看命令的詳細用法介紹。例如,我想看下 echo 的用法和各種選項。可以執行 。執行結果如下: 如果單獨執行 echo 命令,就會列印出一個空白行。 預設情況下,echo 都會換行,如果不想換行的話,可以使用下麵兩種方式 ...
一. 創建互動式腳本
使用 echo命令的選項
關於各種命令的使用,可以使用man 命令
來查看命令的詳細用法介紹。例如,我想看下 echo 的用法和各種選項。可以執行 man echo
。執行結果如下:
如果單獨執行 echo 命令,就會列印出一個空白行。
預設情況下,echo 都會換行,如果不想換行的話,可以使用下麵兩種方式的一種。
echo -n "Which directory do you want to use? "
echo -e "Which directory do you want to use? \c"
使用 read 命令
如果我們需要讀入用戶輸入的參數時,可以使用 read 命令,當然還可以從文件系統等讀入信息。
我們建立一個新的腳本文件 hello3.sh。
#!/bin/bash
echo -n "Hello I $(basename $0) may I ask your name: "
read
echo "Hello $REPLY"
exit 0
執行此腳本時,首先提示需要輸入,然後輸入的內容,REPLY
當沒有給read
提供參數時設置,最後列印出來。
執行結果為:
優化 read 提示的腳本
在前面的例子中,我們使用了echo -n
的方式來阻止信息換行,其實 read 命令也帶了一個選項來實現相同的功能:
read -p "Enter your name: " name
上面的腳本中,我們定義了一個變數name
用來保存輸入的內容,如果不定義變數的話,輸入的內容會保存在REPLY
中。
下麵是具體使用的語法:
hello3.sh的腳本可以改成如下:
#!/bin/bash
read -p "May I ask your name: " name
echo "Hello $name"
exit 0
限制輸入內容的個數
我們還可以使用 read命令的-n 選項,此選項後面需要接一個數字,可以限制輸入內容的個數。
#!/bin/bash
read -p "May I ask your name: " name
echo "Hello $name"
read -n1 -p "Press any key to exit"
echo
exit 0
控制輸入內容的可見性
目前,我們輸入的內容都是可見的,但有些敏感的數據,如密碼,信用卡號等信息,輸入時並不想可見。那麼可以使用read -s
。
這時再輸入時,就有一個鑰匙的標識,而且輸入時不可見。
實例演示
現在有一個小程式,要求把指定尾碼的文件備份到指定的目錄下,代碼如下:
#!/bin/bash
# Script to prompt to back up files and location
# The files will be search on from the user's home
# directory and can only be backed up to a directory within $HOME
read -p "Which file types do you want to backup " file_suffix
read -p "Which directory do you want to backup to " dir_name
# The next lines creates the directory if it does not exist
test -d $HOME/$dir_name || mkdir -m 700 $HOME/$dir_name
# The find command will copy files the match the
# search criteria ie .sh . The -path, -prune and -o
# options are to exclude the back directory from the
# backup.
find $HOME -path $HOME/$dir_name -prune -o \
-name "*$file_suffix" -exec cp {} $HOME/$dir_name/ \;
exit 0
二. 條件判斷語句
使用test 內建函數
test命令是 shell 環境中用於測試條件表達式的工具。
它的返回值可以是 true,false,0或1。基本語法為:
test EXPRESSION
如果我們需要多個表達式,可以使用AND
,OR
,對應的選項為-a
,-o
。
test EXPRESSION -a EXPRESSION
test EXPRESSION -o EXPRESSION
其實,在實際應用中,test 有種非常簡潔的方式,就是被中括弧包含的條件表達式。這種方式更加常用。語法如下:
[ EXPRESION ]
test 的用法很多,例如,可以比較兩個字元串是否相等:
[ $USER = root ]
我們還可以test 的選項來判斷一個字元串的長度是否為0。
[ -z $1 ]
上面的代碼的含義是,如果沒有參數輸入的話,返回 true。
test 還可以用來比較數字的大小。例如:
[ $# -gt 0 ]
除此而外,還可以判斷文件的類型。例如,我們想查找類型為符號鏈接的文件,然後刪除。可以使用如下腳本:
# [ -h $HOME/bin ] &&rm $HOME/bin
其他常用的選項如下:
- -d:文件是否為目錄
- -e:文件是否存在
- -x:文件是否可以執行
- -f:文件是否為常規文件
- -r:文件是否可讀
- -p:文件是否為命名管道
- -b:文件是否為塊設備文件
- -c:文件是否為字元設備文件
使用 if 條件判斷語句
if 語句的基本格式為:
if conditon ; then
statement 1
statement 2
fi
我們可以看一個具體的例子:
#!/bin/bash
if [ $# -lt 1 ] ; then
echo "Usage: $0 <name>"
exit 1
fi
echo "Hello $1"
exit 0
在運行此腳本時,如果沒有輸入參數,則提示正確的使用方法,非正常退出;否則,列印輸入的參數,程式正常退出。
if 語句還可以使用 else 條件分支。具體的語法為:
if conditon ; then
statement
else
statement
fi
我們新建一個腳本文件 hello6.sh,來展示 if else 的用法。
#!/bin/bash
if [ $# -lt 1 ] ; then
read -p "Enter a name: "
name=$REPLY
else
name=$1
fi
echo "Hello $name"
exit 0
當沒有輸入參數時,程式提示需要輸入一個 name;如果輸入了的話,就會列印出來。
最後一種 if 的情況,也是最完整的 if 條件語句。語法如下;
if condition; then
statement
elif condition; then
statement
else
statement
fi
再舉個例子,新建腳本 backup2.sh,我們使用 tar 命令來備份壓縮指定的目錄,根據輸入的參數“H”,“M”,“L”,可以執行不同的壓縮級別。
如果輸入的參數為“H”,則使用 bzip2的壓縮方式;
如果輸入的參數為“M”,則使用 gzip 的壓縮方式;
如果輸入的參數為“L”,則使用 tar 命令對文件打包,不壓縮。
#!/bin/bash
# this sciprt dirs’ location are defualt under $HOME
read -p "Choose H, M or L compression " file_compression
read -p "Which directory do you want to backup to " dir_name
read -p "Which directory do you went to backup: " tobe_backup_name
# The next lines creates the directory if it does not exist
test -d $HOME/$dir_name || mkdir -m 700 $HOME/$dir_name
backup_dir=$HOME/$dir_name
tar_l="-cvf $backup_dir/b.tar $HOME/$tobe_backup_name"
tar_m="-czvf $backup_dir/b.tar.gz $HOME/$tobe_backup_name"
tar_h="-cjvf $backup_dir/b.tar.bzip2 $HOME/$tobe_backup_name"
if [ $file_compression = "L" ] ; then
tar_opt=$tar_l
elif [ $file_compression = "M" ]; then
tar_opt=$tar_m
else
tar_opt=$tar_h
fi
tar $tar_opt
exit 0
使用 case 選擇語句
如果 if else 分支太多的話,可以考慮使用 case 語句,case 語句提供了更加簡潔的機制。
case 語句的語法結構為:
case expression in
case1)
statement1
statement2
;;
case2)
statement1
statement2
;;
*)
statement1
;;
esac
還是舉個簡單的例子,新建腳本文件 grade.sh。
#!/bin/bash
# Script to evaluate grades
# Usage: grade.sh studentName grade
if [ ! $# -eq2 ] ; then
echo "You must provide <studentName> <grade>
exit 2
fi
case $2 in
[A-C]|[a-c])
echo "$1 is a star pupil"
;;
[Dd])
echo "$1 needs to try a little harder!"
;;
[E-F]|[e-f])
echo "$1 could do a lot better next year"
;;
*)
echo "Grade could not be evaluated for $1"
esac
exit 0
運行結果如下:
三. 一些註意事項
我們前面已經介紹過 test 內置命令用來判斷條件語句,但通常我們會推薦使用[]來替代 test 命令。例如:
[ -f /etc/hosts -a -r /etc/hosts ]
但這裡面有個問題,例如,下麵的腳本中,文件名中有空格,我們都知道,空格在命令行中有特殊的用處,用來分割命令選項和參數等。下麵的代碼會報錯。
FILE="my file"
[ -f $FILE -a -r $FILE ] && cat $FILE
報錯信息為“too many arguments”,原因是程式把帶有空格的文件名解析成了兩部分。
而這時,我們需要把變數用雙引號包含起來,
FILE="my file"
[ -f "$FILE" -a -r "$FILE" ] && cat "$FILE"
那有沒有好的辦法可以不使用雙引號呢?當然有的,那就是使用“[[”關鍵字。
“[[”並不是所有的 shell 都支持,它不相容Bourne Shell。我們可以用 type 命令來查看它的類型。
上面的腳本中的[]內的雙引號就可以不用了,但要註意的是 cat 里的雙引號還是要有的。
FILE="my file"
[[ -f $FILE && -r $FILE ]] && cat "$FILE"
“[[”還有其他高級的功能:
1. 模式匹配
例如,我們需要判斷 Perl 腳本,然後做其他的操作,那麼就可以這樣寫:
[[ $FILE = *.pl ]] && cp "$FILE" scripts/
2. 正則表達式
我們可以使用“=~”來匹配正則表達式。我們可以用正則表達式重寫上面的腳本。
$ [[ $FILE =~ \.pl$ ]] &&cp "$FILE" scripts/
我們還可以使用“(())”運算符來做一些簡單的運算。
1. 簡單的數學運算
我們可以使用“((”做一些簡單的數學運算,它可以替代 let 這個內置命令。下麵兩行的代碼執行結果是一樣的。
a=(( 2 + 3 ))
let a=2+3
2. 用在迴圈累加或累減中
這種方式更加常用,
COUNT=1
(( COUNT++ ))
echo $COUNT
3. 用於運算檢查中
我們也可以把“((”用在 test 判斷條件中,我們可以是用“>” 符號,來替代“-gt”。
(( COUNT > 1 )) && echo "Count is greater than 1"
四. 迭代迴圈
迴圈語句是任何一門語言都不能缺失的部分。shell 里也是一樣,只是語法不太一樣。如果學過其他的編程語言,就很容易掌握。
1. for 迴圈
for 迴圈的語法疾結構為:
for f in * ; do
statement "$f"
done
這裡的 f 就是迭代的元素,* 可以是一個數組或是 list,也可以是命令管道。
還有另外一種寫法:
for f in *
do
statement "$f"
done
可以根據自己的喜好選擇一種寫法。
新建一個腳本文件,列印出所有輸入的參數:
#!/bin/bash
echo "You are using $(basename $0)"
for n in $*
do
echo "Hello $n"
done
exit 0
運行結果如下:
在迴圈中,可以使用continue
和break
關鍵字,具體用法與其他語言里是一樣的。continue
表示在迴圈體內,跳過當前迴圈,執行下次的迴圈;而break
表示退出整個迴圈,後面的迴圈和代碼不再執行。
看具體看例子。
$ for f in * ; do
[ -d "$f" ] || continue
chmod 3777 "$f"
done
如果是目錄,添加許可權;如果不是,跳過當前迴圈,continue 後面代碼不再執行,而是直接執行下次迴圈。
$ for f in * ; do
[ -d "$f" ] && break
done
echo "We have found a directory $f"
上面的腳本,在迴圈中一旦發現目錄,則立即停止迴圈並退出。
2. while 迴圈
while 迴圈可以說是 for 迴圈的一個變體,只要特定條件為真,while
語句就會執行。具體看例子,
COUNT=10
while (( COUNT >= 0 )) ; do
echo -e "$COUNT \c"
(( COUNT-- ))
done ;
echo
3. until 迴圈
until
迴圈與while
語句的功能正好相反:只要特定條件為假,它就重覆。下麵是一個與前面的 while
迴圈具有同等功能的 until
迴圈。
COUNT=10
until (( COUNT < 0 )) ; do
echo -e "$COUNT \c"
(( COUNT-- ))
done ;
echo
4. 實例聯繫
現在,我們做一個用戶選擇界面,這樣,根據提示輸入不同的參數來執行不同的功能,這裡我們需要用到while
迴圈,和前面講過的case
條件選擇。
#!/bin/bash
while true ; do
clear
echo "Choose an item: a, b or c"
echo "a: Backup"
echo "b: Display Calendar"
echo "c: Exit"
read -sn1
case "$REPLY" in
a) tar -czvf $HOME/backup.tgz ${HOME}/JavaSource;;
b) cal;;
c) exit 0;;
esac
read -n1 -p "Press andy key to continue"
done
根據提示,如果輸入 a 的話,則把 home 目錄下的 JavaSource 目錄壓縮打包。
輸入b,顯示當前月份。
輸入c,程式退出。