shell總結

主要是語法層面,不過多關注詳細命令。主要是給自己參考用。

變量

只讀變量

使用 readonly 命令可以將變量定義爲只讀變量,只讀變量的值不能被改變。

rword="hello"
echo ${rword}
readonly rword
rword="bye" #運行時報錯

刪除變量

使用 unset 命令可以刪除變量。unset 命令不能刪除只讀變量。

dword="hello"
echo ${dword}
# Output: hello
unset dword
echo ${dword}
# Output: (空)

變量類型

  • 局部變量 - 局部變量只有在變量所在的代碼塊或者函數中才可見,需要使用 local 聲明;
  • 全局變量 - 用戶自定義的普通變量默認是全局變量,可以在本文件中的其它位置引用;
  • 環境變量 - 所有的程序(包括shell啓動的程序)都能訪問環境變量。如果一個shell腳本設置了環境變量,需要用 export 命令來通知腳本的環境。

環境變量 $RANDOM 表示一個 0 到 32767 之間的隨機整數

字符串

單引號和雙引號

shell 字符串可以用單引號 '',也可以用雙引號 "",也可以不用引號。

  • '' :單引號裏的任何字符都會原樣輸出,單引號中對變量引用是無效的,且單引號中不能出現單引號;
  • "":雙引號裏可以引用變量,可以出現轉義字符。

獲取字符串長度

text="12345"
echo ${#text}
# Output:
# 5

截取子串

${string:position} 在string中, 從位置position開始提取子串
${string:position:length} 在string中, 從位置position開始提取長度爲length的子串

查找子串

#!/usr/bin/env bash

text="hello"
echo `expr index "${text}" ll`

# Output: 3

expr 的其他幾種用法:

> expr length "this is a test"
14
> expr substr "this is a test" 3 5
is is
 > expr 14 % 9
 5
 > expr 30 \* 3
 90

刪除子串

表達式 含義
${string#substring} 從string的開頭,刪除最短匹配substring的子串
${string##substring} 從string的開頭,刪除最長匹配substring的子串
${string%substring} 從string的結尾,刪除最短匹配substring的子串
${string%%substring} 從string的結尾,刪除最長匹配substring的子串

注:substring 可以是正則表達式。

替換子串

表達式 含義
${string/substring/replacement} 使用 replacement 來代替第一個匹配的 substring
${string//substring/replacement} 使用 replacement 代替所有匹配的 substring
${string/#substring/replacement} 如果 string 的前綴匹配 substring,那麼就用 replacement 來代替匹配到的 substring
${string/%substring/replacement} 如果 string 的後綴匹配 substring,那麼就用 replacement 來代替匹配到的 substring

數組

bash 只支持一維數組。數組下標從 0 開始,下標可以是整數或算術表達式,其值應大於或等於 0。

創建數組

# 創建數組的不同方式
nums=([2]=2 [0]=0 [1]=1)
colors=(red yellow "dark blue")
arr_name[0]=value1
arr_name[1]=value2
arr_name[23]=value3

獲得數組長度

echo ${#nums[*]}
# Output: 3

echo ${#nums[@]}
# Output: 3

訪問數組元素

  • 訪問數組的單個元素:
echo ${nums[1]}
# Output: 1
  • 訪問數組的所有元素:
echo ${colors[*]}
# Output: red yellow dark blue

echo ${colors[@]}
# Output: red yellow dark blue

上面兩行有很重要(也很微妙)的區別,爲了將數組中每個元素單獨一行輸出,我們用 printf 命令:

printf "+ %s\n" ${colors[*]}
# Output:
# + red
# + yellow
# + dark
# + blue

爲什麼 dark 和 blue 各佔了一行?嘗試用引號包起來:

printf "+ %s\n" "${colors[*]}"
# Output:
# + red yellow dark blue

現在所有的元素都在一行輸出 —— 這不是我們想要的!讓我們試試 ${colors[@]}

printf "+ %s\n" "${colors[@]}"
# Output:
# + red
# + yellow
# + dark blue

在引號內,${colors[@]} 將數組中的每個元素擴展爲一個單獨的參數;數組元素中的空格得以保留。

  • 訪問數組的部分元素:
echo ${nums[@]:0:2}
# Output: 0 1

向數組中添加元素

colors=(white "${colors[@]}" green black)
echo ${colors[@]}
# Output:
# white red yellow dark blue green black

從數組中刪除元素

用 unset 命令來從數組中刪除一個元素:

unset nums[0]
echo ${nums[@]}
# Output: 1 2

控制語句

循環控制

for 循環

for arg in elem1 elem2 ... elemN
do
  # 語句
done

在每次循環的過程中,arg 依次被賦值爲從 elem1elemN 。這些值還可以是通配符或者大括號擴展。
當然,我們還可以把for循環寫在一行,但這要求do之前要有一個分號,就像下面這樣:

for i in {1..5}; do echo $i; done

也可以像 c 語言那樣使用 for,比如:

for (( i = 0; i < 10; i++ )); do
  echo $i
done

while 循環

while [[ condition ]]
do
  # 語句
done

until 循環

x=0
until [[ ${x} -ge 5 ]]; do
  echo ${x}
  x=`expr ${x} + 1`
done

select

select 幫助我們組織一個用戶菜單:

select answer in elem1 elem2 ... elemN
do
  # 語句
done

select 會打印 elem1…elemN 以及它們的序列號到屏幕上,之後會提示用戶輸入。提示符是 $PS3。用戶的選擇結果會被保存到answer 中。

break 和 continue

如果想提前結束一個循環或跳過某次循環執行,可以使用 shell 的 breakcontinue 語句來實現。它們可以在任何循環和 select 中使用。

函數

bash 函數定義語法如下:

[function] funname [()] {
    action;
    [return int;]
}

說明:
1.函數定義時,function 關鍵字可有可無。
2.函數返回值類型只能爲整數(0-255)。如果不加 return 語句,shell 默認將以最後一條命令的運行結果,作爲函數返回值。
3.函數返回值在調用該函數後通過 $? 來獲得。
4.所有函數在使用前必須定義。

位置參數是在調用一個函數並傳給它參數時創建的變量。

變量 描述
$1 … $9 第 1 個到第 9 個參數
${10} … ${N} 第 10 個到 N 個參數
$* or $@ 所有位置參數
$# 位置參數的個數
$FUNCNAME 函數名稱(僅在函數內部有值)

⌨️ 示例:

calc(){
  PS3="choose the oper: " # 選擇菜單的提示符
  select oper in + - \* / # 生成操作符選擇菜單
  do
    echo -n "enter first num: " && read x # 讀取輸入參數
    echo -n "enter second num: " && read y # 讀取輸入參數
    case ${oper} in
      "+")
        return $((${x} + ${y}))
        ;;
      "-")
        return `expr ${x} - ${y}`
        ;;
      "*")
        return `expr ${x} \* ${y}`
        ;;
      "/")
        return $((${x} / ${y}))
        ;;
      *)
        echo "${oper} is not support!"
        return 0
        ;;
    esac
    break
  done
}
calc
echo "the result is: $?" # $? 獲取 calc 函數返回值

Shell 擴展

大括號擴展

大括號擴展讓生成任意的字符串成爲可能。它跟文件名擴展很類似,舉個例子:

echo beg{i,a,u}n # begin began begun

大括號擴展還可以用來創建一個可被循環迭代的區間:

echo {0..5} # 0 1 2 3 4 5
echo {00..8..2} # 00 02 04 06 08 00到8, 2爲步長

命令置換

命令置換允許我們對一個命令求值,並將其值置換到另一個命令或者變量賦值表達式中。當一個命令被``或$()包圍時,命令置換將會執行。舉個例子:

now=`date +%T`
now=$(date +%T)
echo $now

算數擴展

在 bash 中,執行算數運算是非常方便的。算數表達式必須包在$(( ))中。算數擴展的格式爲:

result=$(( ((10 + 5*3) - 7) / 2 ))
echo $result

在算數表達式中,使用變量無需帶上$前綴:

x=4
y=7
echo $((x + y))     # 11
echo $(( ++x + y++ )) # 12
echo $((x + y))     # 13

單引號和雙引號

單引號和雙引號之間有很重要的區別。在雙引號中,變量引用或者命令置換是會被展開的。在單引號中是不會的。舉個例子:

echo "Your home: $HOME" # Your home: /Users/<username>
echo 'Your home: $HOME' # Your home: $HOME

當局部變量和環境變量包含空格時,它們在引號中的擴展要格外注意。舉個例子:

INPUT="A string  with   strange    whitespace."
echo $INPUT   # A string with strange whitespace.
echo "$INPUT" # A string  with   strange    whitespace.

調用第一個 echo 時給了它 5 個單獨的參數 —— $INPUT 被分成了單獨的詞,echo 在每個詞之間打印了一個空格。第二種情況,調用 echo 時只給了它一個參數(整個$INPUT 的值,包括其中的空格)。

括號

小括號中的命令將會新開一個子 shell 順序執行,括號中多個命令之間用分號隔開,最後一個命令可以沒有分號,各命令和括號之間不必有空格。

[ 是 bash 的內部命令,和 test 等同。這個命令把它的參數作爲比較表達式或者作爲文件測試,並且根據比較的結果來返回一個退出狀態碼

[[ 是 bash 程序語言的關鍵字。並不是一個命令,[[ ]] 結構比 [ ] 結構更加通用。使用 [[ … ]] 條件判斷結構,而不是 [ … ],能夠防止腳本中的許多邏輯錯誤。比如,&&、||、< 和 > 操作符能夠正常存在於 [[ ]] 條件判斷結構中,但是不能出現在 [ ] 結構中。

重定向

operator description
> 重定向輸出
2> 重定向錯誤輸出
&> 重定向輸出和錯誤輸出
&>> 以附加的形式重定向輸出和錯誤輸出
< 重定向輸入
<< Here 文檔,從多行輸入
<<< Here 字符串 ,從字符串輸入

冒號是bash的一個內置命令,它什麼效果都沒有,<<是輸入重定向,兩個EOF(可用其它特殊成對字符替代)之間的內容通過<<輸入給冒號(:),就相當於註釋了:

:<<EOF
echo '這是多行註釋'
echo '這是多行註釋'
echo '這是多行註釋'
EOF

Debug

如果想採用 debug 模式運行某腳本,可以在其 shebang 中使用一個特殊的選項:

#!/bin/bash options

options 是一些可以改變 shell 行爲的選項。比如 -v 表示 verbose ,在執行每條命令前,向 stderr 輸出該命令 ,-x 表示 xtrace,在執行每條命令前,向 stderr 輸出該命令以及該命令的擴展參數。
有時我們值需要 debug 腳本的一部分。這種情況下,使用 set 命令會很方便。這個命令可以啓用或禁用選項。使用 - 啓用選項,+ 禁用選項:

# 開啓 debug
set -x
for (( i = 0; i < 3; i++ )); do
  echo ${i}
done
# 關閉 debug
set +x
for i in {1..5}; do printf ${i}; done
printf "\n"

參考

一篇文章讓你徹底掌握 shell 語言
Bash Shell編程入門
shell中的括號(小括號,中括號,大括號)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章