【筆記】bash指令碼
Bash介紹:
Bash(GNU Bourne-Again Shell)是一個為 GNU 計劃編寫的 Unix shell,它是許多 Linux 平臺預設使用的 shell。
解釋性語言,指令碼語言,膠水語言(可以通過將系統呼叫、公共程式、工具和編譯過的二進位制程式”粘合“在一起來建立應用)。
Shell 指令碼對於管理系統任務和其它的重複工作的例程來說,表現的非常好,根本不需要那些華而不實的成熟緊湊的編譯型程式語言。
第一個指令碼:
#!/bin/bash
# hello.sh 註釋
echo Hello World!
其中#!/bin/bash確定檔案型別,echo列印。
執行方式:
# 使用shell來執行
sh hello.sh
# 使用bash來執行
bash hello.sh
# 使用.來執行
. ./hello.sh
# 使用source來執行
source hello.sh
# 還可以賦予指令碼所有者執行許可權,允許該使用者執行該指令碼
chmod u+rx hello.sh
./hello.sh
重定向:
重定向符號">",/dev/null是黑洞,裡面是空的。
#!/bin/bash # 初始化一個變數 LOG_DIR=/var/log cd $LOG_DIR cat /dev/null > dpkg.log echo "Logs cleaned up." exit
如何加許可權:
sudo cat /dev/null > /var/log/dpkg.log
許可權不夠,因為cat有了sudo許可權,而>沒有。
使用sudo sh -c "cat /dev/null > /var/log/dpkg.log"
可以讓整個命令都有sudo許可權。
bash特殊符號:
註釋:
#!/bin/bash echo "The # here does not begin a comment." echo 'The # here does not begin a comment.' echo The \# here does not begin a comment. echo The # 這裡開始一個註釋 echo $(( 2#101011 )) # 數制轉換(使用二進位制表示),不是一個註釋,雙括號表示對於數字的處理
分號;
可以在一行寫兩個及以上命令
#!/bin/bash
echo hello; echo there
filename=ttt.sh
if [ -e "$filename" ]; then # 注意: "if"和"then"需要分隔,-e用於判斷檔案是否存在
echo "File $filename exists."; cp $filename $filename.bak
else
echo "File $filename not found."; touch $filename
fi; echo "File test complete."
雙分號;;
可以終止case選項
#!/bin/bash
varname=b
case "$varname" in
[a-z]) echo "abc";;
[0-9]) echo "123";;
esac
點號.
等價於source,讀取並執行
source test.sh
. test.sh
引號
單引號比雙引號更強烈,阻止解釋。
#!/bin/bash
HOME='hello'
echo HOME # hello
echo "$HOME" # hello
echo '$HOME' # $HOME
斜線/
路徑分割(多個/和一個/是一樣的),以及作為除號。
反斜線\
轉義或者續行。
反引號`
反引號內的會優先執行
cp `mkdir back` test.sh back
ls
冒號:
空命令,等價於true,比如
#!/bin/bash
while :
do
echo "endless loop"
done
可以在if then中做佔位符
#!/bin/bash
condition=5
if [ $condition -gt 0 ] #gt表示greater than,也就是大於,同樣有-lt(小於),-eq(等於)
then : # 什麼都不做,退出分支
else
echo "$condition"
fi
在與 > 重定向操作符結合使用時,將會把一個檔案清空,但是並不會修改這個檔案的許可權。如果之前這個檔案並不存在,那麼就建立這個檔案。
:> test.sh # 檔案“test.sh”現在被清空了
# 與 cat /dev/null > test.sh 的作用相同
# 然而,這並不會產生一個新的程序, 因為“:”是一個內建命令
在與 >> 重定向操作符結合使用時,將不會對預先存在的目標檔案 : >> target_file 產生任何影響。如果這個檔案之前並不存在,那麼就建立它。
: 還用來在 /etc/passwd 和 $PATH 變數中做分隔符,如:
echo $PATH # /usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/sbin:/usr/sbin:/usr/games
問號?
三元運算子
美元符號$
變數替換。有時候$variable
會引起錯誤,可以用${variable}
。
小括號()
在括號中的命令列表,將會作為一個子 shell 來執行。
父程序,也就是指令碼本身,將不能夠讀取在子程序中建立的變數,也就是在子 shell 中建立的變數。
陣列初始化:
#!/bin/bash
arr=(1 4 5 7 9 21)
echo ${arr[3]} # get a value of arr
大括號{}
檔名擴充套件
注意: 在大括號中,不允許有空白,除非這個空白被引用或轉義。
#!/bin/bash
if [ ! -w 't.txt' ]; then
touch t.txt
fi
echo 'test text' >> t.txt
cp t.{txt,back}
程式碼塊:
程式碼塊,又被稱為內部組,這個結構事實上建立了一個匿名函式(一個沒有名字的函式)。然而,與“標準”函式不同的是,在其中宣告的變數,對於指令碼其他部分的程式碼來說還是可見的。
#!/bin/bash
a=123
{ a=321; }
echo "a = $a" # 321
中括號[]
條件檢測,或者選擇陣列元素。前面已經有用到了。
尖括號>
除了>重定向外,&>表示重定向stdout和stderr到檔案中,test.sh &> filename
。>&2
表示重定向stdout到stderr中,test.sh >&2
。test.sh >> filename
:把 test.sh 的輸出追加到檔案 filename 中。如果 filename 不存在的話,將會被建立。
豎線|
管道,分析前邊命令的輸出,並將輸出作為後邊命令的輸入。這是一種產生命令鏈的好方法。
破折號-
選項,字首。在所有的命令內如果想使用選項引數的話,前邊都要加上“-”。比如-eq。
波浪號~
表示Home目錄。
運算
變數命名
定義時變數名和等號之間不能有空格。引用時最好都加大括號,${variable}
。
readonly 只讀
a=5
readonly a
位置引數
$0
表示指令碼自身,$1
表示第一個引數,$2
,$3
類推$#
: 傳遞到指令碼的引數個數$*
: 以一個單字串顯示所有向指令碼傳遞的引數。與位置變數不同,此選項引數可超過9個$$
: 指令碼執行的當前程序 ID 號$!
: 後臺執行的最後一個程序的程序 ID 號[email protected]
: 與 $*
相同,但是使用時加引號,並在引號中返回每個引數$:
: 顯示 shell 使用的當前選項,與 set 命令功能相同$?
: 顯示最後命令的退出狀態。 0 表示沒有錯誤,其他任何值表明有錯誤
一二級計算
原生 bash 不支援簡單的數學運算,但是可以通過其他命令來實現,例如 awk 和 expr。
val=`expr $a + $b`
val=`expr $a \* $b`
if [ $a != $b ]
then
echo "a != b"
fi
注意使用反引號。乘號需要轉義。
表示式和運算子之間要有空格 $a + $b
寫成 $a+$b
不行。
條件表示式要放在方括號之間,並且要有空格 [ $a == $b ]
寫成 [$a==$b]
不行。
關係運算
-eq檢查兩數相等,相等返回true。
-ne檢查相等,不相等返回true。
-gt大於,-lt小於,-ge大於等於,-le小於等於。
&&邏輯與,||邏輯或。
=比較特殊,判斷字串相等。(數字相等是==)
!=判斷不等。
-z判斷字串長度是否為0。
-n判斷字串長度是否不為0。不為0返回true。
str檢測字串是否為空,不為空返回true。
if [ $a ]
then
echo "$a : The string is not empty"
else
echo "$a : The string is empty"
fi
檔案測試運算子
浮點運算
expr 只能用於整數計算,可以使用 bc 或者 awk 進行浮點數運算。
#!/bin/bash
radius=2.4
pi=3.14159
girth=$(echo "scale=4; 3.14 * 2 * $radius" | bc)
area=$(echo "scale=4; 3.14 * $radius * $radius" | bc)
echo "girth=$girth"
echo "area=$area"
bc安裝:
sudo apt-get update
sudo apt-get install bc
分支語句
經常和test命令一起用。
num1=$[2*3]
num2=$[1+5]
if test $[num1] -eq $[num2]
then
echo 'Two numbers are equal!'
else
echo 'The two numbers are not equal!'
fi
迴圈語句
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done
for str in This is a string
do
echo $str
done
以下使用了 Bash let 命令,它用於執行一個或多個表示式,變數計算中不需要加上 $ 來表示變數。
#!/bin/bash
int=1
while(( $int<=5 ))
do
echo $int
let "int++"
done
讀取鍵盤資訊。
echo 'press <CTRL-D> exit'
echo -n 'Who do you think is the most handsome: '
while read MAN
do
echo "Yes! $MAN is really handsome"
done
無限迴圈:
while :
do
command
done
# 或者
while true
do
command
done
# 或者
for (( ; ; ))
until迴圈。至少執行一次。
until condition
do
command
done
break,continue和其他語言一樣。
case分支
取值後面必須為單詞 in,每一模式必須以右括號結束。取值可以為變數或常數。匹配發現取值符合某一模式後,其間所有命令開始執行直至 ;;。
取值將檢測匹配的每一個模式。一旦模式匹配,則執行完匹配模式相應命令後不再繼續其他模式。如果無一匹配模式,使用星號 * 捕獲該值,再執行後面的命令。
echo 'Enter a number between 1 and 4:'
echo 'The number you entered is:'
read aNum
case $aNum in
1) echo 'You have chosen 1'
;;
2) echo 'You have chosen 2'
;;
3) echo 'You have chosen 3'
;;
4) echo 'You have chosen 4'
;;
*) echo 'You did not enter a number between 1 and 4'
;;
esac
case 的語法和 C family 語言差別很大,它需要一個 esac(就是 case 反過來)作為結束標記,每個 case 分支用右圓括號,用兩個分號表示 break。
函式
函式定義:
[ function ] funname [()]
{
action;
[return int;]
}
可以帶 function fun() 定義,也可以直接 fun() 定義,不帶任何引數。
引數返回,可以顯示加:return 返回,如果不加,將以最後一條命令執行結果,作為返回值。 return 後跟數值 n(0-255)
#!/bin/bash
funWithReturn(){
echo "This function will add the two numbers of the input..."
echo "Enter the first number: "
read aNum
echo "Enter the second number: "
read anotherNum
echo "The two numbers are $aNum and $anotherNum !"
return $(($aNum+$anotherNum))
}
funWithReturn
echo "The sum of the two numbers entered is $? !"
函式返回值在呼叫該函式後通過 $? 來獲得。
所有函式在使用前必須定義。
帶引數的函式呼叫示例。
#!/bin/bash
funWithParam(){
echo "The first parameter is $1 !"
echo "The second parameter is $2 !"
echo "The tenth parameter is $10 !"
echo "The tenth parameter is ${10} !"
echo "The eleventh parameter is ${11} !"
echo "The total number of parameters is $# !"
echo "Outputs all parameters as a string $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73
set -e:執行的時候如果出現了返回值為非零,整個指令碼 就會立即退出
set +e:執行的時候如果出現了返回值為非零將會繼續執行下面的指令碼