入門 shell 從腳本開始 - lazy_find


編寫腳本實如今指定文件路徑下查找文件夾或文件名。
 
腳本以下:
#!/bin/sh
# lazy find
 
# GNU All-Permissive License
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved.  This file is offered as-is,
# without any warranty.
 
## help function
 
function helpu {
    echo " "
    echo "Fuzzy search for filename."
    echo "$0 [--match-case|--path] filename"
    echo " "
    exit
}
 
## set variables
 
MATCH="-iname"
SEARCH="."
 
## parse options
 
while [ True ]; do
if [ "$1" = "--help" -o "$1" = "-h" ]; then
    helpu
elif [ "$1" = "--match-case" -o "$1" = "-m" ]; then
    MATCH="-name"
    shift 1
elif [ "$1" = "--path" -o "$1" = "-p" ]; then
    SEARCH="${2}"
    shift 2
else
    break
fi
done
 
## sanitize input filenames
## create array, retain spaces
 
ARG=( "${@}" )
set -e
 
## catch obvious input error
 
if [ "X$ARG" = "X" ]; then
    helpu
fi
 
## perform search
 
for query in ${ARG[*]}; do
    /usr/bin/find "${SEARCH}" "${MATCH}" "*${ARG}*"
done
該腳原本自網絡,很是簡潔,優雅。
 
經過該腳原本學習 shell,腳本中包括以下幾個 shell 知識點:
  • Shebang 行
  • 變量
  • 循環
  • 列表
  • 參數
  • 函數
  • 判斷
  • set
## Shebang 行
Shebang 行是腳本的第一句,一般記爲 #!/bin/bash 這種形式,指定執行該腳本須要用到的解釋器。若是不加,在執行腳本的時候可經過命令 /bin/bash 指定。
 
## 變量
變量在 shell 中寫做 variable=value 的形式(等號兩邊不能有空格!),variable 爲變量名,value 爲變量的值。
 
變量名需遵照如下命名規則:
  • 由字母,數字,下劃線組成。
  • 變量名開頭不能是數字,能夠是字母或下劃線。
  • 變量名中不容許出現空格和標點符號。
 
shell 將全部 value 看做字符串,若是 value 有空格,則需使用引號將 value 括起來。
 
經常使用的幾種變量寫法:
MATCH="-iname"
MATCH=-iname
 
NAME="lian hua"
 
可經過在變量名前加美圓符 $ 或加大括號 ${variable} 的形式引用變量:
echo $MATCH
 
echo ${MATCH}
 
注意,bash 讀取不存在的變量,不會報錯,會打印出空字符,以下:
[lianhuasheng@demo home]$ echo $lianhua
 
[lianhuasheng@demo home]$ 
 
在腳本執行的時候,若是變量不存在通常會指望腳本報錯,這時候 set 命令就派上用場了。
 
## set
set 可用來設置子 shell 的運行環境,不加任何參數的 set 會 show 出當前 shell 的自帶環境變量和自定義環境變量等。另外一方面,set 也可用來編寫更安全的 shell 腳本。
 
set -e 命令可以使得在其後執行的命令,若是失敗了即報錯,後續的命令將不被執行。若是指望命令執行失敗後,後續命令還能繼續執行,可打開 set +e 選項:
set -e
 
command1
command2
 
set +e
 
set -u 可以使得bash 在讀取不存在變量的時候報錯。
 
## 循環
在上例中使用到了 while 和 for 循環:
 
while 循環的語法格式以下:
while condition; do
    commands
done
 
for 循環的語法格式有三種,分別是:
## 1. normal for script
for variable in list; do
    commands
done
 
## demo for script 
#!/bin/bash
 
for i in lian hua sheng; do
  echo $i
done
 
## 2. c style for script
for (( expression1; expression2; expression3 )); do
  commands
done
其中,c 語言風格的 for 循環中,expression1 用來設置循環初始值,expression2 用來設置循環結束條件,expression3 用來更新值。
 
## 列表
上小節看到 for 循環中的循環體是 list 列表,列表可經過大括號擴展或者參數傳遞等的形式取得。
 
# 大括號擴展
使用大括號擴展 {start..end} 形式擴展值爲列表:
[lianhuasheng@demo home]$ echo {1..10}
1 2 3 4 5 6 7 8 9 10
 
將擴展出的列表運用於 for 循環中:
[lianhuasheng@demo home]$ echo {1..10}
1 2 3 4 5 6 7 8 9 10

 

注意,默認 echo 輸出的文本文件後加 \n 換行符,因此這裏指定 echo 的 -n 選項取消換行符。
 
# 參數傳遞
除了大括號擴展,還有一種常見的組成列表的形式是參數傳遞。參數傳遞,即在執行腳本時指定的參數,shell 腳本中分別使用以下幾種符號代表參數:
  • $0: 腳本文件名。
  • $1 - $9: 腳本的第 1 個參數到第 9 個參數,超過 9 個參數使用 ${10}, ${11}... 形式表示。
  • $#: 傳入腳本的參數數量。
  • $@: 傳入腳本中的所有參數,它是一個列表。
[lianhuasheng@demo home]$ cat parameter.sh
#!/bin/bash
# script.sh
 
echo "all parameters:" $@
echo "number of parameters:" $#
echo '$0 = ' $0
echo '$1 = ' $1
echo '$2 = ' $2
echo '$3 = ' $3
 
[lianhuasheng@demo home]$ ./parameter.sh lian hua
all parameters: lian hua
number of parameters: 2
$0 =  ./parameter.sh
$1 =  lian
$2 =  hua
$3 =                            # $3 沒有讀取參數,並無報錯
 
在 for 循環中經常使用 $@ 做爲循環體:
for value in "$@"; do
    echo ${value}
done
 
## 數組
for 循環中還可將數組做爲循環體,在上例腳本中看到這樣一條語句 ARG=("$@"),其中圓括號 () 便是將字符串轉爲數組的符號。
 
# 建立數組
建立數組有多種方式:直接賦值,間接賦值,外部賦值等方式:
 
1. 直接賦值:
[lianhuasheng@demo home]$ arg=(lian hua sheng)
[lianhuasheng@demo home]$ echo ${arg[@]}
lian hua sheng
 
2. 間接賦值:
[lianhuasheng@demo home]$ arg[0]=da
[lianhuasheng@demo home]$ arg[1]=shuai
[lianhuasheng@demo home]$ arg[2]=ge
[lianhuasheng@demo home]$ echo ${arg[@]}
da shuai ge
 
3. 外部賦值:
[lianhuasheng@demo home]$ read -a arg
hei hei hei
[lianhuasheng@demo home]$ echo ${arg[@]}
hei hei hei
 
外部賦值經過使用 read 命令,將用戶的輸入讀入到數組 arg 中。
 
# 讀取數組
通用的讀取數組中的元素有兩種方式:讀取單個元素和讀取全部元素:
 
1. ${arg[index]} 讀取單個元素:
[lianhuasheng@demo home]$ echo ${arg[@]}
da shuai ge
[lianhuasheng@demo home]$ echo ${arg[1]}
shuai
 
2. 讀取全部元素:
[lianhuasheng@demo home]$ echo ${arg[@]}
da shuai ge
 
[lianhuasheng@demo home]$ echo ${arg[*]}
da shuai ge
 
經過 ${array[@]} 和 ${array[*]} 均可讀取數組的全部元素,$array[*] 至關於不加雙引號的 $array[@],加不加雙引號的區別可看下例:
[lianhuasheng@demo home]$ arg=(lian "hua sheng" da "shuai-ge")
 
[lianhuasheng@demo home]$ for value in ${arg[*]}; do echo "parameter: " ${value}; done
parameter:  lian
parameter:  hua
parameter:  sheng
parameter:  da
parameter:  shuai-ge
 
[lianhuasheng@demo home]$ for value in "${arg[*]}"; do echo "parameter: " ${value}; done
parameter:  lian hua sheng da shuai-ge
 
[lianhuasheng@demo home]$ for value in ${arg[@]}; do echo "parameter: " ${value}; done
parameter:  lian
parameter:  hua
parameter:  sheng
parameter:  da
parameter:  shuai-ge
 
[lianhuasheng@demo home]$ for value in "${arg[@]}"; do echo "parameter: " ${value}; done
parameter:  lian
parameter:  hua sheng
parameter:  da
parameter:  shuai-ge
 
從示例中能夠看出,當 $array[@] 加上雙引號以後可正確輸出數組 arg 中的元素,不加雙引號的 $array[@] 和 $array[*] 的結果一致,加了雙引號的 $array[*] 會將數組中全部元素做爲單個字符串返回。
 
注意,不加索引讀取數組元素讀到的是第一個數組元素:
[lianhuasheng@demo home]$ echo $arg
lian
[lianhuasheng@demo home]$ echo ${arg}
lian
[lianhuasheng@demo home]$ echo $arg[0]
lian[0]
[lianhuasheng@demo home]$ echo ${arg}[0]
lian[0]
 
經過 $arg 和 ${arg} 兩種方式讀取數組第一個元素,一般兩種方式讀取變量的結果是一致的,不過推薦使用 ${ } 這種方式讀取變量,它能夠精確界定變量名稱的範圍。
若是讀取變量時不用大括號,則 bash 會解析 $arg, 而後將 [0] 原樣輸出。
 
## 條件判斷
條件判斷是使用 if..elif..fi 根據指定條件判斷命令執不執行的判斷語句,它的語法以下:
if conditions; then
    commands
elif conditions; then
    commands
else
    commands
fi
 
其中,elif 和 else 是可選的。
 
條件判斷有多種判斷表達式,以下:
  • 文件判斷
  • 字符串判斷
  • 整數判斷
  • 正則判斷
  • test 判斷邏輯運算
  • 算術判斷
  • 普通命令的邏輯運算
 
這裏,腳本中的判斷表達式皆屬於字符串判斷,其判斷表達式爲:
  • [ string ]:string 不爲空,則判斷爲真。
  • [ string1 = string2 ]:string1 和 string2 字符串相同則判斷爲真,同 [ string1 == string2 ]。
  • [ string1 != string2 ]:string1 和 string2 不一樣則判斷爲真。
  • [ -n string ]:string 長度大於 0 則判斷爲真。
  • [ -z string ]:string 長度等於 0 則判斷爲真。
 
注意,這裏判斷表達式也使用到了 test 命令,test 有三種形式,分別是:
# 1 style of test
test expression
 
# 2 style of test
[ expression ]
 
# 3 style of test
[[ expression ]]
 
因此,[ -n string ] 判斷表達式又可寫成 test -n string 這種形式。
 
關於其它判斷表達式的使用可看這裏
 
## 函數
shell 中有兩種函數寫法:
# 1 style of function
function fn {
    commands
}
 
# 2 style of function
fn() {
    commands
}
 
介紹函數主要從如下幾個角度入手:函數參數,函數返回值和函數變量:
 
# 函數參數
一般執行腳本傳遞的參數便可做爲函數的參數,可是函數也支持自定義傳參:
#!/bin/bash
 
function input_param {
    echo "I am input function, the input parameters are: "
    echo "$@"
}
 
function input_defined_param {
    echo "I am input defined function, the defined parameters are: "
    echo "The first parameter is: " "${1}"
    echo "The second parameter is: " "${2}"
    echo "The totally parameters are: " "${@}"
}
 
input_param ${@}
input_defined_param lian hua
 
和腳本中參數相似,函數中也可以使用 ${1}/${@}/$#/$* 等參數符號。可是,函數使用特殊參數環境做爲本身的參數值,它沒法直接獲取腳本在命令行中的參數值。所以,須要傳遞參數給函數。
 
# 函數返回值
函數中可以使用 return 返回函數執行結果,在調用函數以後可以使用 $? 查看函數返回結果:
[lianhuasheng@demo home]$ ./function_return.sh
127
[lianhuasheng@demo home]$ cat function_return.sh
#!/bin/bash
 
function_return() {
    return 127
}
 
function_return
echo $?
 
其中,$? 是 bash 提供的特殊變量,它是上一條命令的退出碼,若是 $? 爲 0 則表示命令執行成功,非零表示執行失敗:
[lianhuasheng@demo home]$ cd lianhua
-bash: cd: lianhua: No such file or directory
[lianhuasheng@demo home]$ echo $?
1
 
[lianhuasheng@demo home]$ cd query/
[lianhuasheng@demo query]$ echo $?
0
 
除了 return 返回函數結果以外,在函數或者腳本中也可以使用 exit 返回退出碼,bash 會讀取返回的退出碼,而且腳本 exit 以後的語句不會被執行。
[lianhuasheng@demo home]$ cat function_exit.sh
#!/bin/bash
 
function_exit() {
    exit 127
}
 
function_exit
echo "kissMe"
[lianhuasheng@demo home]$ ./function_exit.sh       # echo "kissMe" 沒有執行到
[lianhuasheng@demo home]$ echo $?
127
[lianhuasheng@demo home]$ vi function_exit.sh
[lianhuasheng@demo home]$ ./function_exit.sh
[lianhuasheng@demo home]$ echo $?
0
 
# 函數變量
函數中聲明的變量都是全局變量,可以使用 local 將變量轉爲局部變量:
[root@demo bash]# cat function_variable.sh
#!/bin/bash
 
name="lian hua"
 
function rename {
    echo "My original name is: " "${name}"
    name="${1}"
    echo "Now, My name is: " "${name}"
}
 
function naming {
    initName="lao wang"
}
 
naming
echo ${initName}                   # 函數外可使用函數內定義的變量
 
rename "shuai ge"
echo "once again, my name is: " "${name}"          # 函數內能夠修改函數外定義的全局變量
 
[root@demo bash]# ./function_variable.sh
lao wang
My original name is:  lian hua
Now, My name is:  shuai ge
once again, my name is:  shuai ge
 
[root@demo bash]# cat function_variable.sh
#!/bin/bash
function naming {
    firstName="wang"
    local lastName="lao"
}
 
naming
echo ${firstName}
 
set -eux
echo ${lastName}
set +eux
 
[root@demo bash]# ./function_variable.sh
wang
./function_variable.sh: line 12: lastName: unbound variable         # lastName 是局部變量,沒法引用
相關文章
相關標籤/搜索