shell能夠在直接在命令行下輸入,也能夠保存成shell腳本文件運行。當命令簡單而且不須要重複使用,在命令行輸入直接執行便可,不然就寫成腳本。shell腳本默認文件擴展名爲.sh
。在shell腳本中,寫入的內容,會默認當成一條命令來執行。html
例如:linux
#!/bin/bash echo 'hello world'
將上面的代碼存爲test.sh,並將可執行權限賦予它chmod +x test.sh
,執行./test.sh
運行腳本。shell
上面的腳本將會輸出:編程
hello world數組
這和在命令行或者終端模擬器下輸入echo 'hello world'
並按下回車獲得的結果是同樣的bash
和全部的編程語言同樣,shell也有註釋,在shell中,#號和它後面的內容來表示一個註釋:編程語言
# Print a message echo "I'm a shell script."
echo用於向輸出流輸出內容,例如:函數
echo "hello world"
read用於輸入一條內容:.net
read input echo $input
上面的代碼中,read命令從輸入流讀取一個值並賦予input,而後將input的內容打印出來命令行
變量的命名規則和C語言差很少,支持英文字母和下劃線。shell中變量名前不須要聲明類型,變量名後面不能有空格,例如:
var1='hello' var2=90
$後接變量名意爲讀取一個變量的值,例如:
var="hello" echo $var
也能夠用${var}
方式訪問到變量值,例如:
var="hello" echo ${var}
訪問變量的時候
$var
和${var}
是等效的,推薦後者來訪問一個變量
沒有任何命令修飾的變量是一個全局變量,全局變量在同一個shell會話中都是有效的。
function func(){ a=90 } func echo $a
輸出:
90
$ a=90 $ echo ${a} $ bash $ echo ${a}
輸出:
90
空值
local命令用於聲明一個局部變量
function func(){ local a=90 } func echo $a
輸出:
空值
用export命令修飾的變量稱爲環境變量,在父shell會話中聲明一個環境變量,子shell中均可以訪問
$ export path="/system/bin" $ bash #建立一個新的shell會話 $ echo ${path}
變量 | 含義 |
---|---|
$0 | 當前腳本的文件名 |
$n(n≥1) | 傳遞給腳本或函數的參數。n 是一個數字,表示第幾個參數。例如,第一個參數是 $1,第二個參數是 $2 |
$# | 傳遞給腳本或函數的參數個數 |
$* | 傳遞給腳本或函數的全部參數 |
$@ | 傳遞給腳本或函數的全部參數 |
$? | 上個命令的退出狀態,或函數的返回值 |
$$ | 當前 Shell 進程 ID。對於 Shell 腳本,就是這些腳本所在的進程 ID |
#!/bin/bash for val in "$*" do echo "\$@ : ${val}" done for val in "$@" do echo "\$* : ${val}" done
假如將上面的代碼存爲test.sh
,運行./test.sh 1 2 3
將輸出:
$@ : 1 2 3 $* : 1 $* : 2 $* : 3
` 這個符號,在鍵盤上的位置是在Esc鍵的下方
ret=`pwd` echo ${ret}
在 ` 包裹起來的命令中,也能夠訪問到變量
path='/' ret=`ls -l ${path}` echo ${ret}
ret=$(pwd) echo ${ret}
用$(command)這種方式也能夠訪問到變量
path='/' ret=$(ls -l ${path}) echo ${ret}
上面的例子中,若是想打印命令結果中的換行符,則:
path='/' ret=$(ls -l ${path}) echo "${ret}"
$(command)方式來執行命令更加直觀,可是要注意,$(command) 僅在 Bash Shell 中有效,而反引號可在多種 Shell 中均可使用
shell有三種方式能夠表示字符串
str=hello echo ${str}
輸出:
hello
這種方式的字符串遇到空格就會被終止
str=hello echo '${str}'
輸出:
${str}
單引號裏的內容是字符串原始的樣子,不存在轉義
str=shell echo "${str}:\"hello wolrd\""
輸出:
shell:"hello world"
雙引號中能夠訪問變量和轉義
str="hello" echo ${#str}
輸出:
5
兩個變量放在一塊兒訪問就能夠拼接
a='hello' b='world' c=${a}${b} echo ${c}
輸出:
helloworld
也能夠這樣
echo 'hello'"world"
(1) 從左邊開始截取字符串,格式:${string: start :length}
,length可省略,省略時,是截取到字符串末尾
msg="hello world" echo ${msg: 6: 5}
輸出:
world
(2) 在指定位置截取字符
${string#*chars}
其中,string 表示要截取的字符,chars 是指定的字符(或者子字符串),是通配符的一種,表示任意長度的字符串。chars連起來使用的意思是:忽略左邊的全部字符,直到碰見 chars(chars 不會被截取)。
截取最後一次出現chars的位置後面的內容:${string##*chars}
使用 % 截取左邊字符
使用%號能夠截取指定字符(或者子字符串)左邊的全部字符,具體格式以下:
${string%chars*}
請注意 * 的位置,由於要截取 chars 左邊的字符,而忽略 chars 右邊的字符,因此 * 應該位於chars的右側。其餘方面%和#的用法相同
運算符 | 做用 |
---|---|
+ | 加(須要結合expr命令使用) |
- | 減(須要結合expr命令使用) |
* | 乘(須要結合expr命令使用) |
/ | 除(須要結合expr命令使用) |
% | 求餘(須要結合expr命令使用) |
= | 賦值 |
== | 判斷數值是否相等,須要結合[] 使用 |
!= | 判斷數值是否不相等,須要結合[] 使用 |
a=8 b=4 echo "a=$a,b=$b" var=`expr ${a} + ${b}` echo "加法結果:${var}" var=`expr ${a} - ${b}` echo "減法結果:${var}" # 注意:乘號須要轉義 var=`expr ${a} \* ${b}` echo "乘法結果:${var}" var=`expr ${a} / ${b}` echo "除法結果:${var}" var=`expr ${a} % ${b}` echo "求餘結果:${var}" var=$[${a} == ${b}] echo "是否相等:${var}" var=$[${a} != ${b}] echo "是否不相等:${var}"
輸出:
a=8,b=4 加法結果:12 減法結果:4 乘法結果:32 除法結果:2 求餘結果:0 是否相等:0 是否不相等:1
上面的例子中,調用expr命令和使用[]
,獲得表達式的值,並將它們輸出
請注意表達式兩邊的空格,shell中表達式兩邊要有空格
運算符 | 做用 |
---|---|
-eq | 全稱:Equal,判斷兩個數是否相等 |
-ne | 全稱:Not equal,判斷兩個數是否不相等 |
-gt | 全稱:Greater than,判斷前面那個數是否大於後面那個數 |
-lt | 全稱:Less than,判斷前面那個數是否小於後面那個數 |
-ge | 全稱:Greater equal,判斷前面那個數是否大於等於後面那個數 |
-le | 全稱:Less than,判斷前面那個數是否小於等於後面那個數 |
運算符 | 做用 |
---|---|
! | 非運算 |
-o | 或運算 |
-a | 並運算 |
運算符 | 做用 |
---|---|
&& | 邏輯並 |
|| |
邏輯或 |
&&
鏈接起來的兩個命令,前面的執行失敗就不執行後面的命令cd /bin && ls /bin
其實和C語言中的是差很少的,只要前面的條件不知足,後面那個就不用去執行它了
||
鏈接起來的兩個命令,前面的執行失敗纔會執行後面的命令cd /bin || ls /bin
在這裏順便說一下;
這個運算符,這個運算符用於鏈接多個語句,使多個語句可以在同一行。用;
鏈接起來的語句,無論前面的執行成不成功,都會執行後面的
mkdir luoye;cd luoye;pwd
運算符 | 做用 |
---|---|
-e | 判斷對象是否存在 |
-d | 判斷對象是否存在,而且爲目錄 |
-f | 判斷對象是否存在,而且爲常規文件 |
-L | 判斷對象是否存在,而且爲符號連接 |
-h | 判斷對象是否存在,而且爲軟連接 |
-s | 判斷對象是否存在,而且長度不爲0 |
-r | 判斷對象是否存在,而且可讀 |
-w | 判斷對象是否存在,而且可寫 |
-x | 判斷對象是否存在,而且可執行 |
-O | 判斷對象是否存在,而且屬於當前用戶 |
-G | 判斷對象是否存在,而且屬於當前用戶組 |
-nt | 判斷file1是否比file2新 |
-ot | 判斷file1是否比file2舊 |
(1) if語句
if語句格式以下:
if <condition> then #do something elif <condition> then #do something else #do something fi
若是想把then和if放同一行
if <condition> ; then #do something elif <condition> ; then #do something else #do something fi
其中elif和else能夠省略
例子:
read file if [ -f ${file} ] ; then echo 'This is normal file.' elif [ -d ${file} ] ; then echo 'This is dir' elif [ -c ${file} -o -b ${file} ] ; then echo 'This is device file.' else echo 'This is unknown file.' fi
邏輯判斷也能夠用test命令,它和[]
的做用是同樣的
#!/bin/bash a=4 b=4 if test $[a+1] -eq $[b+2] then echo "表達式結果相等" else echo "表達式結果不相等" fi
輸出:
表達式結果不相等
(2) for 語句
if語句格式以下:
for <var> in [list] do # do something done
例子:
read input for val in ${input} ; do echo "val:${val}" done
輸入:
1 2 3 4 5
輸出:
val:1
val:2
val:3
val:4
val:5
(3) while 語句
while <condition> do #do something done
例子:
a=1 sum=0 while [ ${a} -le 100 ] ;do sum=`expr ${sum} + ${a}` a=`expr ${a} + 1` done echo ${sum}
輸出:
5050
shell中也有數組,數組的格式是用英文小括號元素包裹起來,元素與元素以前用若干個分割符隔開(空格,製表符,換行符),這個分割符定義在IFS
變量中,咱們能夠經過設置IFS變量自定義分隔符。來看看如何定義一個數組:
array=(1 2 3 4 5 'hello')
也能夠定義一個空數組
array=()
訪問和修改數組元素的格式以下:
array[index]=value
和大多數編程語言同樣,shell的數組索引也是從0開始的,假如想要分別修改數組的第一個和第二個元素爲88和77:
array[0]=88 array[1]=77
上面的代碼,若是array爲空,88和77將被添加到數組中。
遍歷數組太常見了,若是想對數組每一個元素都進行特定的操做(訪問,修改)就須要遍歷。
在shell中,有兩個方式能夠獲得數組的所有元素,${array_name[*]}
和${array_name[@]}
,有了這個知識,咱們就遍歷數組了
#!/bin/bash array=("My favoriate number is" 65 22 ) idx=0 for elem in ${array[*]} do echo "Array element ${idx} is:${elem}" idx=$(expr $idx + 1) done
輸出:
Array element 0 is:My Array element 1 is:favoriate Array element 2 is:number Array element 3 is:is Array element 4 is:65 Array element 5 is:22
在上面的代碼中咱們可能覺得本身定義了一個字符串和兩個數字在數組中,應該打印出一行字符串和兩個數字。可是卻不是這樣的,只要有空白符,shell會把它們當成數組的分隔符,這些被隔開的部分就會被當成數組的元素。
function foo(){ # do something... }
function foo(){ local name=$1 local age=$2 echo "My name is ${name},I'm ${age} years old." } foo "luoye" 26
輸出:
My name is luoye,I'm 26 years old.
重定向能夠理解把一個東西傳送到另個地方
重定向符 | 做用 |
---|---|
output > file | 將輸出流重定向到文件 |
output >> file | 將輸出流追加到文件末尾 |
input < file | 將文件的內容重定向到輸入流 |
例子:
echo 'hello' > out.txt echo 'world' >> out.txt cat out.txt
輸出:
hello world
上面的例子,將hello
從輸出流重定向文件,將world
追加到out.txt文件尾,最後用cat命令讀取並打印out.txt的文件內容
重定向符還能夠配合數字(0,1,2)使用
ls / 1> out.txt cat out.txt
執行上面的命令,會將根目錄下的文件名和目錄名輸出到out.txt
ls /luoye 2> out.txt cat out.txt
執行上面的命令,會將執行ls /luoye
命令時的錯誤信息輸出到out.txt
ls /;ls /luoye 2>&1
執行上面的代碼,將錯誤流重定向到輸出流,這種作法在某些場合是頗有用的。
全部重定向到這個文件的內容都會消失,經常同於忽略錯誤輸出。
ls /luoye 2> /dev/null
若是不存在/luoye這個目錄或者文件,就沒有什麼提示
這個文件會不斷產出空的數據,該文件常被dd
命令使用
dd if=/dev/zero of=out.txt bs=1 count=16
從/dev/zero
輸入,輸出到out.txt
,生成一個大小爲16字節的空文件
管道是Linux中的一種跨進程通訊的機制,和重定向不一樣,管道用作進程與進程之間傳送數據。作爲Linux中默認的腳本語言,shell中也是可使用管道的,在shell中,管道用|
表示
(1)使用管道進行數據篩選內容中包含root
的行
ls -l /|grep root
這個例子中,ls命令輸出的內容傳給了grep命令進行篩選
(2)也能夠同時用多個管道
使用多個管道把數據篩選並統計
ls -l /|grep root|wc -l
這個例子中,ls命令輸出的內容傳給了grep命令進行篩選,而後轉給wc命令統計行數。
爲了更好的理解管道,寫兩個腳原本體驗一下:
in.sh文件
#! /bin/bash read msg echo "Receive :${msg}"
out.sh文件
#! /bin/bash echo 'hello'
在命令行中執行./out.sh |./in.sh
輸出:
Receive :hello
符合咱們預期,字符串hello從out.sh傳送到了in.sh