shell簡明教程

shell的格式

shell能夠在直接在命令行下輸入,也能夠保存成shell腳本文件運行。當命令簡單而且不須要重複使用,在命令行輸入直接執行便可,不然就寫成腳本。shell腳本默認文件擴展名爲.sh。在shell腳本中,寫入的內容,會默認當成一條命令來執行。html

例如:linux

#!/bin/bash
echo 'hello world'
  • 第1行 指定shell腳本的解釋器
  • 第2行 執行echo命令

將上面的代碼存爲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的內容打印出來命令行

1. 變量

1.1 定義變量和賦值

變量的命名規則和C語言差很少,支持英文字母和下劃線。shell中變量名前不須要聲明類型,變量名後面不能有空格,例如:

var1='hello'
var2=90

1.2 讀取變量

$後接變量名意爲讀取一個變量的值,例如:

var="hello"
echo $var

也能夠用${var}方式訪問到變量值,例如:

var="hello"
echo ${var}

訪問變量的時候$var${var}是等效的,推薦後者來訪問一個變量

1.3 變量做用域

1.3.1 全局變量

沒有任何命令修飾的變量是一個全局變量,全局變量在同一個shell會話中都是有效的。

function func(){
    a=90
}
func
echo $a

輸出:

90

$ a=90
$ echo ${a}
$ bash 
$ echo ${a}

輸出:

90

空值

1.3.2 局部變量

local命令用於聲明一個局部變量

function func(){
    local a=90
}
func
echo $a

輸出:

空值

1.3.3 環境變量

用export命令修飾的變量稱爲環境變量,在父shell會話中聲明一個環境變量,子shell中均可以訪問

$ export path="/system/bin"
$ bash #建立一個新的shell會話
$ echo ${path}

1.3.4 特殊變量

變量 含義
$0 當前腳本的文件名
$n(n≥1) 傳遞給腳本或函數的參數。n 是一個數字,表示第幾個參數。例如,第一個參數是 $1,第二個參數是 $2
$# 傳遞給腳本或函數的參數個數
$* 傳遞給腳本或函數的全部參數
$@ 傳遞給腳本或函數的全部參數
$? 上個命令的退出狀態,或函數的返回值
$$ 當前 Shell 進程 ID。對於 Shell 腳本,就是這些腳本所在的進程 ID

1.3.5 $*和$@的區別

  • $*獲得全部參數被當成字符串
  • $@獲得全部參數都會被當成獨立的參數
#!/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

2. 獲取一條命令的執行結果

2.1 用 ` 將一條命令包裹起來

` 這個符號,在鍵盤上的位置是在Esc鍵的下方

ret=`pwd`
echo ${ret}

在 ` 包裹起來的命令中,也能夠訪問到變量

path='/'
ret=`ls -l ${path}`
echo ${ret}

2.2 以$(command)這種方式執行命令

ret=$(pwd)
echo ${ret}

用$(command)這種方式也能夠訪問到變量

path='/'
ret=$(ls -l ${path})
echo ${ret}

上面的例子中,若是想打印命令結果中的換行符,則:

path='/'
ret=$(ls -l ${path})
echo "${ret}"

$(command)方式來執行命令更加直觀,可是要注意,$(command) 僅在 Bash Shell 中有效,而反引號可在多種 Shell 中均可使用

3. 字符串

shell有三種方式能夠表示字符串

3.1 字符串的表示

(1)變量名後直接跟上字符

str=hello
echo ${str}

輸出:

hello

這種方式的字符串遇到空格就會被終止

(2)單引號

str=hello
echo '${str}'

輸出:

${str}

單引號裏的內容是字符串原始的樣子,不存在轉義

(3)雙引號

str=shell
echo "${str}:\"hello wolrd\""

輸出:

shell:"hello world"

雙引號中能夠訪問變量和轉義

3.2 獲取字符串的長度

str="hello"
echo ${#str}

輸出:

5

3.3 字符串拼接

兩個變量放在一塊兒訪問就能夠拼接

a='hello'
b='world'
c=${a}${b}
echo ${c}

輸出:

helloworld

也能夠這樣

echo 'hello'"world"

3.4 字符串截取

(1) 從左邊開始截取字符串,格式:${string: start :length},length可省略,省略時,是截取到字符串末尾

msg="hello world"
echo ${msg: 6: 5}

輸出:

world

(2) 在指定位置截取字符

  • 截取chars後面的字符:${string#*chars}

其中,string 表示要截取的字符,chars 是指定的字符(或者子字符串),是通配符的一種,表示任意長度的字符串。chars連起來使用的意思是:忽略左邊的全部字符,直到碰見 chars(chars 不會被截取)。

  • 截取最後一次出現chars的位置後面的內容:${string##*chars}

  • 使用 % 截取左邊字符
    使用%號能夠截取指定字符(或者子字符串)左邊的全部字符,具體格式以下:
    ${string%chars*}

請注意 * 的位置,由於要截取 chars 左邊的字符,而忽略 chars 右邊的字符,因此 * 應該位於chars的右側。其餘方面%和#的用法相同

4. 運算符和流程控制

4.1 基本運算

運算符 做用
+ 加(須要結合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中表達式兩邊要有空格

4.2 關係運算

運算符 做用
-eq 全稱:Equal,判斷兩個數是否相等
-ne 全稱:Not equal,判斷兩個數是否不相等
-gt 全稱:Greater than,判斷前面那個數是否大於後面那個數
-lt 全稱:Less than,判斷前面那個數是否小於後面那個數
-ge 全稱:Greater equal,判斷前面那個數是否大於等於後面那個數
-le 全稱:Less than,判斷前面那個數是否小於等於後面那個數

4.3 布爾運算

運算符 做用
! 非運算
-o 或運算
-a 並運算

4.4 邏輯運算

運算符 做用
&& 邏輯並
|| 邏輯或
  • &&鏈接起來的兩個命令,前面的執行失敗就不執行後面的命令
cd /bin && ls /bin

其實和C語言中的是差很少的,只要前面的條件不知足,後面那個就不用去執行它了

  • ||鏈接起來的兩個命令,前面的執行失敗纔會執行後面的命令
cd /bin || ls /bin

在這裏順便說一下;這個運算符,這個運算符用於鏈接多個語句,使多個語句可以在同一行。用;鏈接起來的語句,無論前面的執行成不成功,都會執行後面的

mkdir luoye;cd luoye;pwd

4.5 文件判斷

運算符 做用
-e 判斷對象是否存在
-d 判斷對象是否存在,而且爲目錄
-f 判斷對象是否存在,而且爲常規文件
-L 判斷對象是否存在,而且爲符號連接
-h 判斷對象是否存在,而且爲軟連接
-s 判斷對象是否存在,而且長度不爲0
-r 判斷對象是否存在,而且可讀
-w 判斷對象是否存在,而且可寫
-x 判斷對象是否存在,而且可執行
-O 判斷對象是否存在,而且屬於當前用戶
-G 判斷對象是否存在,而且屬於當前用戶組
-nt 判斷file1是否比file2新
-ot 判斷file1是否比file2舊

4.6 流程控制語句

(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

5. 數組

5.1 定義和基本用法

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將被添加到數組中。

5.2 遍歷

遍歷數組太常見了,若是想對數組每一個元素都進行特定的操做(訪問,修改)就須要遍歷。

在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會把它們當成數組的分隔符,這些被隔開的部分就會被當成數組的元素。

6. 函數

  1. 用function關鍵字來定義一個函數
  2. 直接寫一個函數名來調用一個無參數的函數
  3. 函數有參數,調用時,在函數名後面寫上參數,多個參數用空格隔開
  4. 調用函數時傳遞參數,在函數體內部,經過 $n的形式來獲取參數的值,例如:$1表示第1個參數,$2表示第2個參數...

6.1 函數的結構

function foo(){
# do something...
}

6.2 函數的用法示例

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.

7. 重定向

重定向能夠理解把一個東西傳送到另個地方

重定向符 做用
output > file 將輸出流重定向到文件
output >> file 將輸出流追加到文件末尾
input < file 將文件的內容重定向到輸入流

7.1 輸出到文件

例子:

echo 'hello' > out.txt
echo 'world' >> out.txt
cat out.txt

輸出:

hello
world

上面的例子,將hello從輸出流重定向文件,將world追加到out.txt文件尾,最後用cat命令讀取並打印out.txt的文件內容

重定向符還能夠配合數字(0,1,2)使用

  • 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

執行上面的代碼,將錯誤流重定向到輸出流,這種作法在某些場合是頗有用的。

7.2 特殊文件

7.2.1 /dev/null

全部重定向到這個文件的內容都會消失,經常同於忽略錯誤輸出。

ls /luoye 2> /dev/null

若是不存在/luoye這個目錄或者文件,就沒有什麼提示

7.2.2 /dev/zero

這個文件會不斷產出空的數據,該文件常被dd命令使用

dd if=/dev/zero of=out.txt bs=1 count=16

/dev/zero輸入,輸出到out.txt,生成一個大小爲16字節的空文件

8. 管道

管道是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

9. 參考

  • http://c.biancheng.net/shell/
  • http://www.runoob.com/linux/linux-shell-process-control.html
  • https://www.cnblogs.com/qlqwjy/p/8684630.html
  • https://blog.51cto.com/skypegnu1/1543319
相關文章
相關標籤/搜索