1. 程式人生 > 其它 >【筆記】bash指令碼

【筆記】bash指令碼

技術標籤:shellpythonlinuxjava程式語言

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 >&2test.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:執行的時候如果出現了返回值為非零將會繼續執行下面的指令碼