日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

一、什么是shell?

shell是一個用 C 語言編寫的程序,它是用戶使用 linux 的橋梁。Shell 既是一種命令語言,又是一種程序設計語言。

Shell 是指一種應用程序,這個應用程序提供了一個界面,用戶通過這個界面訪問操作系統內核的服務。

Shell屬于內置的腳本,程序開發的效率非常高,依賴于功能強大的命令可以迅速地完成開發任務(批處理)語法簡單,代碼寫起來比較輕松,簡單易學。

二、shell的分類

cat /etc/shells

在linux中有很多類型的shell,不同的shell具備不同的功能,shell還決定了腳本中函數的語法,Linux中默認的shell是 /bash/bash(重點),流行的shell有ash、bash、ksh、csh、zsh等,不同的shell都有自己的特點以及用途。

編寫規范:

#!/bin/bash [指定告知系統當前這個腳本要使用的shell解釋器]

Shell相關指令

文件命名規范:

*.sh

.sh是linux下bash shell 的默認后綴

Bash 常用快捷鍵

 

快捷鍵

 

作用

 

ctrl+A

 

把光標移動到命令行開頭。如果我們輸入的命令過長,想要把光標移動到命令行開頭時使用。

 

ctrl+E

 

把光標移動到命令行結尾。

 

ctrl+C

 

強制終止當前的命令。

 

ctrl+L

 

清屏,相當于clear命令。

 

ctrl+U

 

刪除或剪切光標之前的命令。我輸入了一行很長的命令,不用使用退格鍵一個一個字符的刪除,使用這個快捷鍵會更加方便

 

ctrl+K

 

刪除或剪切光標之后的內容。

 

ctrl+Y

 

粘貼ctrl+U或ctul+K剪切的內容。

 

ctrl+R

 

在歷史命令中搜索,按下ctrl+R之后,就會出現搜索界面,只要輸入搜索內容,就會從歷史命令中搜索。

 

ctrl+D

 

退出當前終端。

 

ctrl+Z

 

暫停,并放入后臺。這個快捷鍵牽扯工作管理的內容,我們在系統管理章節詳細介紹。

 

ctrl+S

 

暫停屏幕輸出。

 

ctrl+Q

 

恢復屏幕輸出。

輸入輸出重定向

linux 的標準輸入與輸出

 

設備

 

設備名

 

文件描述符

 

類型

 

鍵盤

 

/dev/stdin

 

0

 

標準輸入

 

顯示器

 

/dev/stdout

 

1

 

標準輸出

 

顯示器

 

/dev/stderr

 

2

 

標準錯誤輸出

輸入重定向

輸入重定向:是指不使用系統提供的標準輸入端口,而進行重新的指定。換言之,輸入重定向就是不使用標準輸入端口輸入文件,而是使用指定的文件作為標準輸入設備。(重定向簡單理解就是使用 “<”符來修改標準輸入設備)

 

類型

 

符號(語法)

 

功能

 

標準輸入

 

命令<文件1

 

命令把文件1的內容作為標準輸入設備

 

標識符限定輸入

 

命令<<標識符

 

命令把標準輸入中讀入內容,直到遇到“標識符”分解符為止

 

輸入輸出重定向(同時使用)

 

命令< 文件1 >文件2

 

命令把文件1的內容作為標準輸入,把文件2作為標準輸出。

輸出重定向

輸出重定向:(通俗的講,重定向輸出就是把要輸出的文件信息寫入到一個文件中去,而不是將要輸出的文件信息輸出到控制臺(顯示屏),在linux中,默認的標準輸出設備是控制臺(或稱為顯示器),用戶輸出的信息默認情況下都會顯示到控制臺.

&表示全部文件,文件不管對錯,1表示標準輸出文件,2表示標準錯誤輸出。

 

類型

 

符號(語法)

 

功能

 

標住輸出重定向

 

命令 > 文件

 

以覆蓋方式,把命令的正確輸出內容輸出到指定的文件或設備當中

 

標住輸出重定向

 

命令 >> 文件

 

以追加方式,把命令的正確輸出內容輸出到指定的文件或設備當中

 

標準錯誤輸出重定向

 

錯誤命令 2> 文件

 

以覆蓋方式,把命令的錯誤輸出輸出到指定的文件或設備當中

 

標準錯誤輸出重定向

 

錯誤命令 2>> 文件

 

以追加方式,把命令的錯誤輸出輸出到指定的文件或設備當中

 

正確輸出和錯誤輸出同時保存

 

命令 > 文件 2>&1

 

以覆蓋的方式,把正確輸出和錯誤輸出都保存到同一個文件當中。

 

正確輸出和錯誤輸出同時保存

 

命令 >> 文件 2>&1

 

以追加的方式,把正確輸出和錯誤輸出都保存到同一個文件當中。

 

正確輸出和錯誤輸出同時保存

 

命令 &> 文件

 

以覆蓋的方式,把正確輸出和錯誤輸出都保存到同一個文件當中。

 

正確輸出和錯誤輸出同時保存

 

命令 &>> 文件

 

以追加的方式,把正確輸出和錯誤輸出都保存到同一個文件當中。

 

正確輸出和錯誤輸出同時保存

 

命令 >> 文件1 2>>文件2

 

把正確的輸出追加到文件1中,把錯誤的輸出追加到文件2中。

/dev/null 文件

如果希望執行某個命令,但又不希望在屏幕上顯示輸出結果,那么可以將輸出重定向到 /dev/null中.

[root@localhost ~]$ command > dev/null

多命令順序執行

 

多命令執行符

 

作用

 

格式

 

 

命令1 ;命令2

 

多個命令順序執行,命令之間沒有任何邏輯聯系

 

&&

 

命令1 && 命令2

 

當命令1正確執行(? = 0 ) , 則命令2才會執行;當命令 1執行不正確(?=0),則命令2不會執行

 

||

 

命令1 || 命令2

 

當命令1執行不正確(?≠0),則命令2才會執行;當命令1正確執行(?≠0),則命令2不會執行.

shell腳本的執行

[root@localhost ~]$ vim test.sh

#!/bin/bash

echo “hello world”

兩種方式執行shell腳本

第一種:給文件增加執行權限

[root@localhost ~]$ chmod u+x test.sh

[root@localhost ~]$ ./test.sh #絕對路徑或相對路徑執行

第二種(了解):通過Bash調用執行腳本

[root@localhost ~]$ bash test.sh

三、shell變量

什么是變量?

在一個腳本周期內,其值可以發生改變的量就是變量。

1. 變量的命名規則:

在定義變量時,有一些規則需要遵守:

l 命名只能使用英文字母,數字和下劃線,首個字符不能以數字開頭。

l 等號左右兩側不能有空格,可以使用下劃線“_”,變量的值如果有空格,需要使用單引號或雙引號包括。如:“test=“hello world!””。其中雙引號括起來的內容“$”,“(”和反引號都擁有特殊含義,而單引號括起來的內容都是普通字符。

l 不能使用標點符號,不能使用bash里的關鍵字(可用help命令查看保留關鍵字)。

l 環境變量建議大寫,便于區分

l 如果需要增加變量的值,那么可以進行變量值的疊加。不過變量需要用雙引號包含"$變量名"或用${變量名}包含變量名。

<!---->

[root@localhost ~]$ test=123

[root@localhost ~]$ test="$test"456

[root@localhost ~]$ echo $test

123456

#疊加變量test,變量值變成了123456

[root@localhost ~]$ test=${test}789

[root@localhost ~]$ echo $test

123456789

#再疊加變量test,變量值編程了123456789

關于單雙引號的問題:

雙引號能夠識別變量,雙引號能夠實現轉義(類似于“*”)

單引號是不能識別變量,只會原樣輸出,單引號是不能轉義的

shell中特殊符號

 

符號

 

作用

 

''

 

單引號。在單引號中所有的特殊符號,如“$”和”(反引號)都沒有特殊含義。單引號括起來的都是普通字符,會原樣輸出

 

""

 

雙引號。在雙引號中特殊符號都沒有特殊含義.“$”表示“調用變量的值”,“`”(esc鍵下面)表示“引用命令”,“”表示“轉義符”。

 

``

 

反引號。反引號括起來的內容是系統命令,在Bash中會先執行它。和()作用一 樣, 不過推薦使用(),因為反引號非常容易看錯。

 

$()

 

和反引號作用一樣,用來引用系統命令。(推薦使用)

 

()

 

用于一串命令執行時,()中的命令會在子Shell中運行

 

{}

 

用于一串命令執行時,{ }中的命令會在當前Shell中執行。也可以用于變量變形與替換。

 

[ ]

 

用于變量的測試。

 

#

 

在Shell腳本中,#開頭的行代表注釋。

 

$

 

用于調用變量的值,如需要調用變量name的值時,需要用$name的方式得到變量的值。

 

 

轉義符,跟在之后的特殊符號將失去特殊含義,變為普通字符。如$將輸出“$”符號,而不當做是變量引用。

單引號和雙引號

[root@localhost ~]$ name=sc

#定義變量name 的值是sc

[root@localhost ~]$ echo '$name'

$name

#如果輸出時使用單引號,則$name被認為是字符串

[root@localhost ~]$ echo "$name"

sc

#如果輸出時使用雙引號,則會輸出變量name的值 sc

 

[root@localhost ~]$ echo `date`

2018年10月21日星期一18:16:33 CST

#反引號括起來的命令會正常執行

[root@localhost ~]$ echo '`date`'

`date`

#但是如果反引號命令被單引號括起來,那么這個命令不會執行,―date`會被當成普通字符輸出

[root@localhost ~]$ echo "`date'"

2018年10月21日星期一18:14:21 CST

#如果是雙引號括起來,那么這個命令又會正常執行

反引號

[root@localhost ~]$ echo ls

ls

#如果命令不用反引號包含,命令不會執行,而是直接輸出

[root@localhost ~]$ echo `ls`

anaconda-ks.cfginstall.loginstall.log.syslog sh test testfile

#只有用反引號包括命令,這個命令才會執行

[root@localhost ~]$ echo $(date)

2018年10月21日星期一18:25:09 CST

#使用$(命令)的方式也是可以的

2. 變量的分類

l 用戶自定義變量: 這種變量是最常見的變量,由用戶自由定義變量名和變量的值。

l 環境變量: 這種變量中主要保存的是和系統操作環境相關的數據,比如當前登錄用戶,用戶的家目錄,命令的提示符等。不是太好理解吧,那么大家還記得在windows中,同一臺電腦可以有多個用戶登錄,而且每個用戶都可以定義自己的桌面樣式和分辨率,這些其實就是Windows的操作環境,可以當做是Windows的環境變量來理解。環境變量的變量名可以自由定義,但是一般對系統起作用的環境變量的變量名是系統預先設定好的。

l 位置參數變量: 這種變量主要是用來向腳本當中傳遞參數或數據的,變量名不能自定義,變量作用是固定的。

l 預定義變量: 是Bash中已經定義好的變量,變量名不能自定義,變量作用也是固定的。

 

變量分類

 

名稱

 

作用

 

內容

 

用戶自定義變量

 

自定義

 

自定義

 

自定義

 

用戶自定義環境變量

 

自定義

 

自定義

 

自定義

 

系統自帶環境變量(/etc/profile)

 

確定

 

確定

 

自定義

 

位置參數變量

 

確定

 

自定義

 

自定義

 

預定義變量

 

確定

 

自定義

 

自定義

2.1 用戶自定義變量

2.1.1 變量定義

[root@localhost ~]$ 2name="shen chao"

-bash: 2name=shen chao: command not found

#變量名不能用數字開頭

[root@localhost ~]$ name = "shenchao"

-bash: name: command not found

#等號左右兩側不能有空格

[root@localhost ~]$ name=shen chao

-bash: chao: command not found

#變量的值如果有空格,必須用引號包含

2.1.2 變量調用

[root@localhost ~]$ name="shen chao"

#定義變量name

[root@localhost ~]$ echo $name #調用變量使用 $變量名

shen chao

#輸出變量name的值

2.1.3 變量查看

[root@localhost ~]$ set [選項]

選項:

-u:如果設定此選項,調用未聲明變量時會報錯(默認無任何提示)

-x:如果設定此選項,在命令執行之前,會把命令先輸出一次

+<參數> :取消某個set曾啟動的參數。

 

[root@localhost ~]$ set

BASH=/bin/bash

…省略部分輸出…

name='shen chao'

#直接使用set 命令,會查詢系統中所有的變量,包含用戶自定義變量和環境變量

[root@localhost ~]$ set -u

[root@localhost ~]$ echo $file

-bash: file: unbound variable

#當設置了-u選項后,如果調用沒有設定的變量會有報錯。默認是沒有任何輸出的。

[root@localhost ~]$ set -x

[root@localhost ~]$ ls

+ls --color=auto

anaconda-ks.cfginstall.loginstall.log.syslog sh tdir testtestfile

#如果設定了-x選項,會在每個命令執行之前,先把命令輸出一次

 

[root@localhost ~]$ set +x

#取消啟動的x參數

2.1.4 變量刪除

[root@localhost ~]$ unset 變量名

2.2 環境變量

2.2.1 環境變量設置

[root@localhost ~]$ export age="18"

#使用export聲明的變量即是環境變量

2.2.2 環境變量查詢和刪除

env命令和set命令的區別

set命令可以查看所有變量,而env命令只能查看環境變量。

[root@localhost ~]$ unset gender #刪除環境變量gender

[root@localhost ~]$ env | grep gender

2.2.3 系統默認環境變量

[root@localhost ~]$ env

HOSTNAME=localhost.localdomain #主機名

SHELL=/bin/bash #當前的shell

TERM=linux #終端環境

HISTSIZE=1000 #歷史命令條數

SSH_CLIENT=192.168.4.15 22 #當前操作環境是用ssh連接的,這里記錄客戶端ip

SSH_TTY=/dev/pts/1 #ssh連接的終端時pts/1

USER=root #當前登錄的用戶

..........更多參數可以使用set和env命令查看.............

2.3 位置參數變量

 

位置參數變量

 

作用

 

$n

 

n為數字,$0表示當前 Shell腳本程序的名稱,$1-9代表 第一到第九個參數 , 十以上的參數需要用大括號包含,如9代表第一到第九個參數,十以上的參數需要用大括號包含,如9代表第一到第九個參數,十以上的參數需要用大括號包含,如${10}

 

$*

 

這個變量代表命令行中所有的參數,$把所有的參數看成一個整體

 

$@

 

這個變量也代表命令行中所有的參數,不過$@把每個參數區分對待

 

$#

 

這個變量代表命令行中所有參數的個數

$1 是你給你寫的shell腳本傳的第一個參數,$2 是你給你寫的shell腳本傳的第二個參數…

[root@localhost sh]$ vim test.sh

#!/bin/sh

echo "shell腳本本身的名字: $0"

echo "傳給shell的第一個參數: $1"

echo "傳給shell的第二個參數: $2"

保存退出后,你在Test.sh所在的目錄下輸入 bash Test.sh 1 2

結果輸出:

shell腳本本身的名字: Test.sh

傳給shell的第一個參數: 1

傳給shell的第二個參數: 2

$*會把接收的所有參數當成一個整體對待,而$@則會區分對待接收到的所有參數。舉個例子:

[root@localhost sh]$ vi parameter2.sh

#!/bin/bash

for i in"$*"

#定義for循環,in后面有幾個值,for會循環多少次,注意“$*”要用雙引號括起來

#每次循環會把in后面的值賦予變量i

#Shell把$*中的所有參數看成是一個整體,所以這個for循環只會循環一次

do

echo "The parameters is: $i"

#打印變量$i的值

done

x=1

#定義變量x的值為1

for y in"$@"

#同樣in后面的有幾個值,for循環幾次,每次都把值賦予變量y

#可是Shel1中把“$@”中的每個參數都看成是獨立的,所以“$@”中有幾個參數,就會循環幾次

do

echo "The parameter$x is: $y"

#輸出變量y的值

x=$(( $x +1 ))

#然變量x每次循環都加1,為了輸出時看的更清楚

done

2.4 預定義變量

 

預定義變量

 

作用

 

$?

 

最后一次執行的命令的返回狀態。如果這個變量的值為0,證明上一個命令正確執行;如果這個變量的值為非О(具體是哪個數,由命令自己來決定),則證明上一個命令執行不正確了。

 

$$

 

當前進程的進程號(PID)

 

$!

 

后臺運行的最后一個進程的進程號(PID)

先來看看”$?”這個變量,舉個例子說明

[root@localhost sh]$ ls

count.sh hello.sh parameter2.sh parameter.sh

#ls命令正確執行

[root@localhost sh]$ echo $?

#預定義變量“$?”的值是0,證明上一個命令執行正確

[root@localhost sh]$ ls install.log

ls:無法訪問install.log:沒有那個文件或目錄

#當前目錄中沒有install.log文件,所以ls命令報錯了

[root@localhost sh]$ echo $?

2

#變量“$?”返回一個非0的值,證明上一個命令沒有正確執行

#至于錯誤的返回值到底是多少,是在編寫ls命令時定義好的,如果碰到文件不存在就返回數值2

再來說明下”$$”和”$!”這兩個預定義變量

[root@localhost sh]$ vi variable.sh

#!/bin/bash

echo "The current process is $$"

#輸出當前進程的PID.

#這個PID就是variable.sh這個腳本執行時,生成的進程的PID

find /root -name hello.sh &

#使用find命令在root目錄下查找hello.sh文件

#符號&的意思是把命令放入后臺執行,工作管理我們在系統管理章節會詳細介紹

echo "The last one Daemon process is $!"

#輸出這個后臺執行命令的進程的PID,也就是輸出find命令的PID號

3. 只讀變量

[root@localhost sh]$ vi readonly.sh

#!/bin/bash

a=10

#語法:readonly 變量名

readonly a

a=20 #會報錯readonly variable

echo $a

4. 接受鍵盤輸入

[root@localhost ~]$ read [選項][變量名]

選項:

-a 后跟一個變量,該變量會被認為是個數組,然后給其賦值,默認是以空格為分割符。

-p: “提示信息”:在等待read輸入時,輸出提示信息

-t: 秒數:read命令會一直等待用戶輸入,使用此選項可以指定等待時間

-n: 數字:read命令只接受指定的字符數,就會執行

-s: 隱藏輸入的數據,適用于機密信息的輸入

-d: 后面跟一個標志符,其實只有其后的第一個字符有用,作為結束的標志。

-e: 在輸入的時候可以使用命令補全功能。

變量名:

變量名可以自定義,如果不指定變量名,會把輸入保存入默認變量REPLY.

如果只提供了一個變量名,則整個輸入行賦予該變量.

如果提供了一個以上的變量名,則輸入行分為若干字,一個接一個地賦予各個變量,而命令行上的最后一個變量取得剩余的所有字

寫個例子來解釋下read命令:

[root@localhost sh]$ vi read.sh

#!/bin/bash

 

read -t 30 -p "Please input your name: " name

#提示“請輸入姓名”并等待30 秒,把用戶的輸入保存入變量name 中

echo "Name is $name"

#看看變量“$name”中是否保存了你的輸入

 

read -s -t 30 -p "Please enter your age: " age

#提示“請輸入年齡”并等待30秒,把用戶的輸入保存入變量age中

#年齡是隱私,所以我們用“-s”選項隱藏輸入

echo -e "n"

#調整輸出格式,如果不輸出換行,一會的年齡輸出不會換行

echo "Age is $age"

 

read -n 1 -t 30 -p "Please select your gender[M/F]:" gender

#提示“請選擇性別”并等待30秒,把用戶的輸入保存入變量gender

#使用“-n1”選項只接收一個輸入字符就會執行(都不用輸入回車)

echo -e "n"

echo "Sex is $gender"

四、shell 運算符

在shell中,運算符和其他編程腳本語言一樣,常見的有算數運算符、關系運算符、邏輯運算符、字符串運算符、文件測試運算符等

1. 算數運算符

原生bash不支持簡單的數學運算,但是可以通過其他命令來實現,例如 awk 和 expr,expr 最常用。

expr 是一款表達式計算工具,使用它能完成表達式的求值操作。

例如,兩個數相加(注意使用的是反引號 ` 而不是單引號 '):

[root@localhost ~]$ vi computer.sh

#!/bin/bash

val=`expr 2 + 2`

echo "兩數之和為 : $val"

#注意

#表達式和運算符之間要有空格,例如 2+2 是不對的,必須寫成 2 + 2,這與我們熟悉的大多數編程語言不一樣。

#完整的表達式要被 ` ` 包含,注意這個字符不是常用的單引號,在 Esc 鍵下邊。

下表列出了常用的算術運算符,假定變量 a 為 10,變量 b 為 20

 

運算符

 

說明

 

舉例

 

+

 

加法

 

expr $a + $b 結果為 30。

 

-

 

減法

 

expr $a - $b 結果為 -10。

 

*

 

乘法

 

expr $a * $b 結果為 200。

 

/

 

除法

 

expr $b / $a 結果為 2。

 

%

 

取余

 

expr $b % $a 結果為 0。

 

=

 

賦值

 

a=$b 將把變量 b 的值賦給 a。

 

==

 

相等。用于比較兩個數字,相同則返回 true(真)。

 

[ $a == $b ] 返回 false(假)。

 

!=

 

不相等。用于比較兩個數字,不相同則返回 true。

 

[ $a != $b ] 返回 true。

注意:條件表達式要放在方括號之間,并且要有空格,必須寫成 [ $a == $b ]。

[root@localhost ~]$ vi computers.sh

#!/bin/bash

a=10

b=20

echo ' '

echo 'a+b= ' `expr $a + $b`

echo 'a-b= ' `expr $a - $b`

echo 'a*b= ' `expr $a * $b`

echo 'a/b= ' `expr $a / $b`

echo 'a%b= ' `expr $a % $b`

 

#判斷是否相等

if [ $a == $b ]

then

echo 'a等于b'

else

echo 'a不等于b'

fi

2. 關系運算符

關系運算符只支持數字,不支持字符串,除非字符串的值是數字。

下表列出了常用的關系運算符,假定變量 a 為 10,變量 b 為 20:

 

運算符

 

單詞

 

說明

 

舉例

 

-eq

 

equal

 

檢測兩個數是否相等,相等返回 true。

 

[ $a -eq $b ] 返回 false。

 

-ne

 

not equal

 

檢測兩個數是否相等,不相等返回 true。

 

[ $a -ne $b ] 返回 true。

 

-gt

 

great than

 

檢測左邊的數是否大于右邊的,如果是,則返回 true。

 

[ $a -gt $b ] 返回 false。

 

-lt

 

less than

 

檢測左邊的數是否小于右邊的,如果是,則返回 true。

 

[ $a -lt $b ] 返回 true。

 

-ge

 

great than or equal

 

檢測左邊的數是否大于等于右邊的,如果是,則返回 true。

 

[ $a -ge $b ] 返回 false。

 

-le

 

less than or equal

 

檢測左邊的數是否小于等于右邊的,如果是,則返回 true。

 

[ $a -le $b ] 返回 true。

[root@localhost ~]$ [ 10 -gt 10 ]

[root@localhost ~]$ echo $?

1

[root@localhost ~]$ [ 10 -eq 10 ]

[root@localhost ~]$ echo $?

0

案例:判斷當前輸入的用戶是否存在。如果存在則提示“用戶存在”否則提示“用戶不存在”。

如果要在shell腳本使用linux命令,可以使用$()包裹命令

例如:disk_size=$(df -h | awk ‘NR==2 {print $5}’)

[root@localhost ~]$ vim demo.sh

#!/bin/bash

#接受用戶的輸入

read -p '請輸入需要查詢的用戶名:' username

 

#獲取指定用戶名在passwd文件中出現的次數

count=$(cat /etc/passwd | grep $username | wc -l)

#count=`cat /etc/passwd | grep $username | wc -l`

 

#判斷出現的次數,如果次數=0則用戶不存在,反之存在

if [ $count == 0 ]

then

echo '用戶不存在'

else

echo '用戶存在'

fi

3. 邏輯運算符

下表列出了常用的布爾運算符,假定變量 a 為 10,變量 b 為 20:

 

運算符

 

說明

 

舉例

 

!

 

非運算,表達式為 true 則返回 false,否則返回 true。

 

[ ! false ] 返回 true。

 

-o

 

或(或者)運算,有一個表達式為 true 則返回 true。

 

[ $a -lt 20 -o $b -gt 100 ] 返回 true。

 

-a

 

與(并且)運算,兩個表達式都為 true 才返回 true。

 

[ $a -lt 20 -a $b -gt 100 ] 返回 false。

或運算:一個為真即為真,全部為假才是假

與運算:一個為假即為假,全部為真才是真

4. 字符串運算符

下表列出了常用的字符串運算符,假定變量 a 為 “abc”,變量 b 為 “efg”:

 

運算符

 

說明

 

舉例

 

=

 

檢測兩個字符串是否相等,相等返回 true。

 

[ $a = $b ] 返回 false。

 

!=

 

檢測兩個字符串是否相等,不相等返回 true。

 

[ $a != $b ] 返回 true。

 

-z

 

檢測字符串長度是否為0,為0返回 true。

 

[ -z $a ] 返回 false。

 

-n

 

檢測字符串長度是否為0,不為0返回 true。

 

[ -n $a ] 返回 true。

 

str

 

檢測字符串是否為空,不為空返回 true。

 

[ $a ] 返回 true。

5. 文件測試運算符(重點)

文件測試運算符用于檢測 Unix/Linux 文件的各種屬性。

 

操作符

 

說明

 

舉例

 

-b file

 

檢測文件是否是塊設備文件,如果是,則返回 true。

 

[ -b $file ] 返回 false。

 

-c file

 

檢測文件是否是字符設備文件,如果是,則返回 true。

 

[ -c $file ] 返回 false。

 

-d file

 

檢測文件是否是目錄,如果是,則返回 true。

 

[ -d $file ] 返回 false。

 

-f file

 

檢測文件是否是普通文件(既不是目錄,也不是設備文件),如果是,則返回 true。

 

[ -f $file ] 返回 true。

 

-g file

 

檢測文件是否設置了 SGID 位,如果是,則返回 true。

 

[ -g $file ] 返回 false。

 

-k file

 

檢測文件是否設置了粘著位(Sticky Bit),如果是,則返回 true。

 

[ -k $file ] 返回 false。

 

-p file

 

檢測文件是否是有名管道,如果是,則返回 true。

 

[ -p $file ] 返回 false。

 

-u file

 

檢測文件是否設置了 SUID 位,如果是,則返回 true。

 

[ -u $file ] 返回 false。

 

-r file

 

檢測文件是否可讀,如果是,則返回 true。

 

[ -r $file ] 返回 true。

 

-w file

 

檢測文件是否可寫,如果是,則返回 true。

 

[ -w $file ] 返回 true。

 

-x file

 

檢測文件是否可執行,如果是,則返回 true。

 

[ -x $file ] 返回 true。

 

-s file

 

檢測文件是否為空(文件大小是否大于0),不為空返回 true。

 

[ -s $file ] 返回 true。

 

-e file

 

檢測文件(包括目錄)是否存在,如果是,則返回 true。

 

[ -e $file ] 返回 true。

注意:權限幾個判斷,如果只有一個部分符合,則認為是有權限的。

五、流程控制

1. if條件判斷

1.1 單分支if條件

語法:

if [ 條件判斷式 ]

then

程序

fi

案例:統計根分區使用率

[root@localhost ~]$ vi sh/if1.sh

#!/bin/bash

#統計根分區使用率

rate=$(df -h | grep "/dev/sda2" | awk '{print $5}’| cut -d "%"-f1)

#把根分區使用率作為變量值賦予變量rate

if [ $rate -ge 80 ]

#判斷rate的值如果大于等于80,則執行then程序

then

echo "Warning!/dev/sda3 is fu11!!"

#打印警告信息。在實際工作中,也可以向管理員發送郵件。

fi

案例:創建目錄

[root@localhost ~]$ vi sh/add_dir.sh

#!/bin/bash

#創建目錄,判斷是否存在,存在就結束,反之創建

echo "當前腳本名稱為$0"

DIR="/media/cdrom"

if [ ! -e $DIR ]

then

mkdir -p $DIR

fi

echo "$DIR 創建成功"

1.2 雙分支if條件語句

語法:

if [ 條件判斷式 ]

then

條件成立時,執行的程序

else

條件不成立時,執行的另一個程序

fi

案例1:備份MySQL數據庫

[root@localhost ~]$ vi sh/bakmysql.sh

#!/bin/bash

#備份mysql數據庫。

 

ntpdate asia.pool.ntp.org &>/dev/null

#同步系統時間

date=$(date +%y%m%d)

#把當前系統時間按照“年月日”格式賦子變量date

size=$(du -sh /var/lib/mysql)

#統計mysql數據庫的大小,并把大小賦予size變量

 

if [ -d /tmp/dbbak ]

#判斷備份目錄是否存在,是否為目錄

then

#如果判斷為真,執行以下腳本

echo "Date : $date!" > /tmp/dbbak/dbinfo.txt

#把當前日期寫入臨時文件

echo "Data size : $size" >> /tmp/dbbak/dbinfo.txt

#把數據庫大小寫入臨時文件

cd /tmp/dbbak

 

#進入備份目錄

tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &> /dev/null

#打包壓縮數據庫與臨時文件,把所有輸出丟入垃圾箱(不想看到任何輸出)

rm -rf /tmp/dbbak/dbinfo.txt

#刪除臨時文件

else

mkdir /tmp/dbbak

#如果判斷為假,則建立備份目錄

echo "Date : $date!" > /tmp/dbbak/dbinfo.txt

echo "Data size : $size" >> /tmp/dbbak/dbinfo.txt

#把日期和數據庫大小保存如臨時文件

cd /tmp/dbbak

tar -zcf mysql-lib-$date.tar. gz dbinfo.txt /var/lib/mysql &> /dev/null

#壓縮備份數據庫與臨時文件

rm -rf/tmp/dbbak/dbinfo.txt

#刪除臨時文件

fi

案例2:判斷Apache是否啟動,如果沒有啟動則自動啟動

[root@localhost ~]$ vi sh/autostart.sh

#!/bin/bash

#判斷apache是否啟動,如果沒有啟動則自動啟動

 

port=$(nmap -sT 192.168.4.210 | grep tcp | grep http | awk '{print $2}')

#使用nmap命令掃描服務器,并截取 apache服務的狀態,賦予變量port

#只要狀態是open,就證明正常啟動

if [ "$port" == "open"]

#如果變量port的值是“open”

then

echo "$(date) httpd is ok!” >> /tmp/autostart-acc.log

#則證明apache 正常啟動,在正常日志中寫入一句話即可

else

/etc/rc.d/init.d/httpd start &>/dev/null

#否則證明apache沒有啟動,自動啟動apache

echo "$(date) restart httpd !!" >> /tmp/autostart-err.log

#并在錯誤日志中記錄自動啟動apche 的時間

fi

nmap端口掃描命令,格式如下:

[root@localhost ~]$ nmap -sT 域名或IP

選項:

-s 掃描

-T 掃描所有開啟的TCP端口

 

#知道了nmap命令的用法,我們在腳本中使用的命令就是為了截取http的狀態,只要狀態是“or.

 

#就證明apache啟動正常,否則證明apache啟動錯誤。來看看腳本中命令的結果:

[root@localhost ~]$ nmap -sT 192.168.4.210 | grep tcp | grep http | awk ' fprint $2}’

#掃描指定計算機,提取包含tcp 的行,在提取包含httpd 的行,截取第二列open

#把截取的值賦予變量port

1.3 多分支if條件語句

語法:

if [ 條件判斷式1 ]

then

當條件判斷式1成立時,執行程序1

elif [ 條件判斷式2 ]

then

當條件判斷式2成立時,執行程序2

…省略更多條件…

else

當所有條件都不成立時,最后執行此程序

fi

案例:判斷用戶輸入的是什么文件

[root@localhost ~]$ vi sh/if-elif.sh

#!/bin/bash

#判斷用戶輸入的是什么文件

 

read -p "Please input a filename: " file

#接收鍵盤的輸入,并賦予變量file

if [ -z "$file” ]

#判斷file變量是否為空

then

echo "Error, please input a filename"

#如果為空,執行程序1,也就是輸出報錯信息

exit 1

#退出程序,并返回值為Ⅰ(把返回值賦予變量$P)

elif [ ! -e "$file” ]

#判斷file的值是否存在

then

echo "Your input is not a file!"

#如1果不存在,則執行程序2

exit 2

#退出程序,把并定義返回值為2

elif [ -f "$file” ]

#判斷file的值是否為普通文件

then

echo "$file is a regulare file!”

#如果是普通文件,則執行程序3

elif [ -d "$file” ]

#到斷file的值是否為目錄文件

then

echo "$file is a directory!"

#如果是目錄文件,網執行程序4

else

echo "$file is an other file!”

#如果以上判斷都不是,則執行程序5

fi

2. 多分支case條件語句

case語句和if…elif…else語句一樣都是多分支條件語句,不過和if多分支條件語句不同的是,case語句只能判斷一種條件關系,而if語句可以判斷多種條件關系。

語法:

case $變量名 in

"值1")

如果變量的值等于值1,則執行程序1

;;

"值2")

如果變量的值等于值2,則執行程序2

::

…省略其他分支…

*)

如果變量的值都不是以上的值,則執行此程序

;;

esac

這個語句需要注意以下內容:

l case語句,會取出變量中的值,然后與語句體中的值逐一比較。如果數值符合,則執行對應的程序,如果數值不符,則依次比較下一個值。如果所有的值都不符合,則執行 “*)” (*代表所有其他值)中的程序。

l case語句以“case”開頭,以“esac”結尾。

每一個分支程序之后要通過“;;”雙分號結尾,代表該程序段結束(千萬不要忘記,每次寫case語句,都不要忘記雙分號)。

案例:

[root@localhost ~]$ vi sh/if-case.sh

#!/bin/bash

read -p "請輸入一個字符,并按Enter確認:" KEY

case "$KEY" in

[a-z]|[A-Z])

echo "您輸入的是字母"

;;

 

[0-9])

echo "您輸入的是數字"

;;

 

*)

echo "您輸入的是其他字符"

;;

esac

3. for循環

for循環是固定循環,也就是在循環時已經知道需要進行幾次的循環,有時也把for循環稱為計數循環。for的語法有如下兩種:

語法一:

for 變量 in 值1 值2 值3 …(可以是一個文件等)

do

程序

done

 

這種語法中for循環的次數,取決于in后面值的個數(空格分隔),有幾個值就循環幾次,并且每次循環都把值賦予變量。

也就是說,假設in后面有三個值,for會循環三次,第一次循環會把值1賦予變量,第二次循環會把值2賦予變量,以此類推。

語法二:

for (( 初始值;循環控制條件;變量變化 ))

do

程序

done

 

語法二中需要注意:

初始值:在循環開始時,需要給某個變量賦予初始值,如i=1;

 

循環控制條件:用于指定變量循環的次數,如i<=100,則只要i的值小于等于100,循環就會繼續;

 

變量變化:每次循環之后,變量該如何變化,如i=i+1。代表每次循環之后,變量i的值都加1。

語法一舉例:打印時間

[root@localhost ~]$ vi sh/for.sh

#!/bin/bash

#打印時間

 

for time in morning noon afternoon evening

do

echo "This time is $time!"

done

語法一舉例:批量解壓縮腳本

[root@localhost ~]$ vi sh/auto-tar. sh

#!/bin/bash

#批量解壓縮腳本

 

cd/lamp

#進入壓縮包目錄

ls *.tar.gz > ls.log

#把所有.tar.gz結尾的文件的文件覆蓋到ls.log 臨時文件中

for i in $(cat ls.log) `

#或者這樣寫for i in `cat ls.log`

 

#讀取ls.log文件的內容,文件中有多少個值,就會循環多少次,每次循環把文件名賦予變量i

do

tar -zxf $i &>/dev/null

#加壓縮,并把所有輸出都丟棄

done

rm -rf /lamp/ls.log

#刪除臨時文件ls.log

語法二舉例:從1加到100

[root@localhost ~]$ vi sh/add. sh

#!/bin/bash

#從1加到100

 

s=0

for (( i=1;i<=100;i=i+1 ))

#定義循環100 次

do

s=$(( $s+$i ))

#每次循環給變量s賦值

done

echo "The sum of 1+2+...+100 is : $s"

#輸出1加到100的和

語法二舉例:批量添加指定數量的用戶

[root@localhost ~]$ vi useradd.sh

#!/bin/bash

#批量添加指定數量的用戶

 

read -p "Please input user name: " -t 30 name

#讓用戶輸入用戶名,把輸入保存入變量name

 

read -p "Please input the number of users: " -t 30 num

#讓用戶輸入添加用戶的數量,把輸入保存入變量num

 

read -p "Please input the password of users: " -t 30 pass

#讓用戶輸入初始密碼,把輸入保存如變量pass

 

if [ ! -z "$name" -a ! -z "$num"-a ! -z "$pass"]

#判斷三個變量不為空

then

y=$(echo $num | sed 's/[0-9]//g')

#定義變量的值為后續命令的結果

#后續命令作用是,把變量num 的值替換為空。如果能替換為空,證明num 的值為數字

#如果不能替換為空,證明num的值為非數字。我們使用這種方法判斷變量num 的值為數字

if [ -z "$y"]

#如果變量y的值為空,證明num變量是數字

then

for (( i=1 ; i<=$num; i=i+1 ))

#循環num變量指定的次數

do

/usr/sbin/useradd $name$i &>/dev/null

#添加用戶,用戶名為變量name 的值加變量i的數字

echo $pass | /usr/bin/passwd --stdin $name$i &>/dev/null

#給用戶設定初始密碼為變量pass 的值

done

fi

fi

語法二舉例:批量刪除用戶

[root@localhost ~]$ vi sh/userdel.sh

#!/bin/bash

#批量刪除用戶

 

user=$(cat /etc/passwd | grep " /bin/bash"|grep -v "root"Icut -d ":" -f 1)

#讀取用戶信息文件,提取可以登錄用戶,取消root用戶,截取第一列用戶名

 

for i in $user

#循環,有多少個普通用戶,循環多少次

do

userdel -r $i

#每次循環,刪除指定普通用戶

done

4. while循環

語法:

while [ 條件判斷式 ]

do

程序

done

案例:1加到100

[root@localhost ~]$ vi sh/addnum.sh

#!/bin/bash

#從1加到100

 

i=1

s=0

#給變量i和變量s賦值

 

while [ $i -le 100 ]

#如果變量i的值小于等于100,則執行循環

do

s=$(( $s+$i ))

i=$(( $i+1 ))

done

echo "The sum is: $s"

案例:輸入的數值進行比較判斷

[root@localhost ~]$ vi sh/addnum.sh

#!/bin/bash

PRICE=$(expr $RANDOM % 1000)

TIMES=0

 

echo "商品的價格為0-999之間,猜猜看是多少?"

while true

do

read -p "請輸入您猜的價格:" INT

let TIMES++

 

if [ $INT -eq $PRICE ] ; then

echo "恭喜您猜對了,實際價格是 $PRICE"

echo "您總共猜了 $TIMES 次"

exit 0

elif [ $INT -gt $PRICE ] ; then

echo "太高了"

else

echo "太低了"

fi

done

5. until循環

和while循環相反,until循環時只要條件判斷式不成立則進行循環,并執行循環程序。一旦循環條件成立,則終止循環。

語法:

until [ 條件判斷式 ]

do

程序

done

案例一:1加到100

[root@localhost ~]$ vi sh/until.sh

#!/bin/bash

#從1加到100

 

i=1

s=0

#t給變量i和變量s賦值

 

until [ $i -gt 100 ]

#循環直到變量i的值大于100,就停止循環

do

s=$(( $s+$i ))

i=$(( $i+1 ))

done

echo "The sum is: $s"

6. 函數

語法:

function 函數名 () {

程序

}

案例:接收用戶輸入的數字,然后從1加到這個數字

[root@localhost ~]$ vi sh/function.sh

#!/bin/bash

#接收用戶輸入的數字,然后從1加到這個數字

 

function sum () {

#定義函數sum

s=0

for (( i=0; i<=$num;i=i+1 ))

#循環直到i大于$1為止。$1是函數sum 的第一個參數

#在函數中也可以使用位置參數變量,不過這里的$1指的是函數的第一個參數

do

s=$(( $i+$s ))

done

echo "The sum of 1+2+3...+$1 is :$s"

#輸出1加到$1的和

}

 

read -p "Please input a number: " -t 30 num

#接收用戶輸入的數字,并把值賦予變量num

y=$(echo $num | sed 's/[0-9]//g')

#把變量num的值替換為空,并賦予變量y

 

if [ -z "$y"]

#判斷變量y是否為空,以確定變量num中是否為數字

then

sum $num

#調用sum函數,并把變量num的值作為第一個參數傳遞給sum函數

else

echo "Error!! Please input a number!"

#如果變量num 的值不是數字,則輸出報錯信息

fi

7. 特殊流程控制語句

7.1 exit語句

系統是有exit命令的,用于退出當前用戶的登錄狀態。可是在Shell腳本中,exit語句是用來退出當前腳本的。也就是說,在Shell腳本中,只要碰到了exit語句,后續的程序就不再執行,而直接退出腳本。

exit的語法如下:

exit [返回值]

如果exit命令之后定義了返回值,那么這個腳本執行之后的返回值就是我們自己定義的返回值。可以通過查詢$?這個變量,來查看返回值。如果exit之后沒有定義返回值,腳本執行之后的返回值是執行exit 語句之前,最后執行的一條命令的返回值。寫一個exit 的例子:

[root@localhost ~]$ vi sh/exit.sh

#!/bin/bash

#演示exit的作用

 

read -p "Please input a number: " -t 30 num

#接收用戶的輸入,并把輸入賦予變量num

y=$ (echo $num | sed 's/[0-9]//g')

#如果變量num 的值是數字,則把num的值替換為空,否則不替換

#把替換之后的值賦予變量y

[ -n "$y" ] && echo "Error! Please input a number!" && exit 18

#判斷變量y的值如果不為空,輸出報錯信息,退出腳本,退出返回值為18

echo "The number is: $num"

#如果沒有退出加班,則打印變量num中的數字

7.2 break語句

當程序執行到break語句時,會結束整個當前循環。而continue 語句也是結束循環的語句,不過continue 語句單次當前循環,而下次循環會繼續。

案例:

[root@localhost ~]$ vi sh/break.sh

#!/bin/bash

#演示break 跳出循環

 

for (( i=1;i<=10; i=i+1 ))

#循環十次

do

if ["$i" -eq 4 ]

#如果變量i的值等于4

then

break

#退出整個循環

fi

echo $i

#輸出變量i的值

done

執行下這個腳本,因為一旦變量i的值等于4,整個循環都會跳出,所以應該只能循環三次:

[root@localhost ~]$ chmod 755 sh/break.sh

[root@localhost ~]#sh/break.sh

1

2

3

7.3 continue語句

continue也是結束流程控制的語句。如果在循環中,continue語句只會結束單次當前循環。

案例:

[root@localhost ~]$ vi sh/break.sh

#!/bin/bash

#演示continue

 

for (( i=1;i<=10;i=i+1 ))

#循環十次

do

if ["$i" -eq 4 ]

#如果變量i的值等于4

then

continue

#退出換成continue

fi

echo $i

#輸出變量i的值

done

執行下這個腳本:

[root@localhost ~]$ chmod 755 sh/continue.sh

[root@localhost ~]#sh/break.sh

1

2

3

5

6

7

8

9

10

#少了4這個輸出

六、字符截取、替換和處理命令

正則表達式

 

元字符

 

描述

 

示例

 

 

轉義符,將特殊字符進行轉義,忽略其特殊意義

 

a.b匹配a.b,但不能匹配ajb,.被轉義為特殊意義

 

^

 

匹配行首,awk中,^則是匹配字符串的開始

 

^tux匹配以tux開頭的行

 

$

 

匹配行尾,awk中,$則是匹配字符串的結尾

 

tux$匹配以tux結尾的行

 

.

 

匹配除換行符n之外的任意單個字符

 

ab.匹配abc或abd,不可匹配abcd或abde,只能匹配單字符

 

[ ]

 

匹配包含在[字符]之中的任意一個字符

 

coo[kl]可以匹配cook或cool

 

[^]

 

匹配[^字符]之外的任意一個字符

 

123[^45]不可以匹配1234或1235,1236、1237都可以

 

[-]

 

匹配[]中指定范圍內的任意一個字符,要寫成遞增

 

[0-9]可以匹配1、2或3等其中任意一個數字

 

?

 

匹配之前的項1次或者0次

 

colou?r可以匹配color或者colour,不能匹配colouur

 

+

 

匹配之前的項1次或者多次

 

sa-6+匹配sa-6、sa-666,不能匹配sa-

 

*

 

匹配之前的項0次或者多次

 

co*l匹配cl、col、cool、coool等

 

()

 

匹配表達式,創建一個用于匹配的子串

 

ma(tri)?匹配max或maxtrix

 

{n}

 

匹配之前的項n次,n是可以為0的正整數

 

[0-9]{3}匹配任意一個三位數,可以擴展為[0-9][0-9][0-9]

 

{n,}

 

之前的項至少需要匹配n次

 

[0-9]{2,}匹配任意一個兩位數或更多位數不支持{n,}{n,}{n,}

 

{n,m}

 

指定之前的項至少匹配n次,最多匹配m次,n<=m

 

[0-9]{2,5}匹配從兩位數到五位數之間的任意一個數字

 

|

 

交替匹配|兩邊的任意一項

 

ab(c|d)匹配abc或abd

1 字符截取、替換命令

1.1 cut 列提取命令

[root@localhost ~]$ cut [選項] 文件名

選項:

-f 列號: 提取第幾列

-d 分隔符: 按照指定分隔符分割列

-n取消分割多字節字符

-c 字符范圍: 不依賴分隔符來區分列,而是通過字符范圍(行首為0)來進行字段提取。“n-”表示從第n個字符到行尾;“n-m”從第n個字符到第m個字符;“一m”表示從第1個字符到第m個字符。

--complement補足被選擇的字節、字符或字段

--out-delimiter指定輸出內容是的字段分割符

cut命令的默認分隔符是制表符,也就是“tab”鍵,不過對空格符可是支持的不怎么好啊。我們先建立一個測試文件,然后看看cut命令的作用吧:

[root@localhost ~]$ vi student.txt

idnamegendermark

1limingm86

2scm67

3tgn90

[root@localhost ~]$ cut -f 2 student.txt

#提取第二列內容

那如果想要提取多列呢?只要列號直接用“,”分開,命令如下:

[root@localhost ~]$ cut -f 2,3 student.txt

如果我想用cut命令截取df命令的第一列和第三列,就會出現這樣的情況:

[root@localhost~]$ df -h | cut -d " " -f 1,3

Filesystem

/dev/sda2

tmpfs

/dev/sda1

1.2 awk 編程

參考:

linux文本處理三劍客:grep,sed及awk

1.2.1 awk 概述

AWK 是一種處理文本文件的語言,是一個強大的文本分析工具。

1.2.2 printf 格式化輸出

[root@localhost ~]$ printf ‘輸出類型輸出格式’ 輸出內容

 

輸出類型:

%c: ASCII字符.顯示相對應參數的第一個字符

%-ns: 輸出字符串,減號“-”表示左對齊(默認右對齊),n是數字指代輸出幾個字符,幾個參數就寫幾個%-ns

%-ni: 輸出整數,n是數字指代輸出幾個數字

%f: 輸出小數點右邊的位數

%m.nf: 輸出浮點數,m和n是數字,指代輸出的整數位數和小數位數。如%8.2f代表共輸出8位數,其中2位是小數,6位是整數。

 

輸出格式:

a: 輸出警告聲音

b: 輸出退格鍵,也就是Backspace鍵

f: 清除屏幕

n: 換行

r: 回車,也就是Enter鍵

t: 水平輸出退格鍵,也就是Tab 鍵

v: 垂直輸出退格鍵,也就是Tab 鍵

為了演示printf命令,我們需要修改下剛剛cut命令使用的student.txt文件,文件內容如下:

[root@localhost ~]$ vi student.txt

ID Name php Linux MySQL Average

1 AAA 66 66 66 66

2 BBB 77 77 77 77

3 CCC 88 88 88 88

 

#printf格式輸出文件

[root@localhost ~]$ printf '%st %st %st %st %st %st n’ $(cat student.txt)

#%s分別對應后面的參數,6列就寫6個

ID Name php Linux MySQL Average

1 AAA 66 66 66 66

2 BBB 77 77 77 77

3 CCC 88 88 88 88

如果不想把成績當成字符串輸出,而是按照整型和浮點型輸出,則要這樣:

[root@localhost ~]$ printf '%it %st %it %it %it %8.2ft n’ $(cat student.txt | grep -v Name)

1.2.3 awk 基本使用

[root@localhost ~]$ awk‘條件1{動作1} 條件2{動作2}…’ 文件名

條件(Pattern):

一般使用關系表達式作為條件。這些關系表達式非常多,例如:

x > 10 判斷變量x是否大于10

x == y 判斷變量x是否等于變量y

A ~ B 判斷字符串A中是否包含能匹配B表達式的子字符串

A !~ B 判斷字符串A中是否不包含能匹配B表達式的子字符串

 

動作(Action) :

格式化輸出

流程控制語句

 

常用參數:

 

-F指定輸入時用到的字段分隔符

-v自定義變量

-f從腳本中讀取awk命令

-m對val值設置內在限制

我們這里先來學習awk基本用法,也就是只看看格式化輸出動作是干什么的。

[root@localhost ~]$ awk '{printf $2 "t" $6 "n"}’ student.txt

#輸出第二列和第六列

比如剛剛截取df命令的結果時,cut命令已經力不從心了,我們來看看awk命令:

[root@localhost ~]$ df -h | awk '{print $1 "t" $3}'

#截取df命令的第一列和第三列

1.2.4 awk 的條件

 

條件的類型

 

條件

 

說明

 

awk保留字

 

BEGIN

 

在awk程序一開始時,尚未讀取任何數據之前執行。BEGIN后的動作只在程序開始時執行一次

 

awk保留字

 

END

 

在awk程序處理完所有數據,即將結束時執行。END后的動作只在程序結束時執行一次

 

關系運算符

 

>

 

大于

 

關系運算符

 

<

 

小于

 

關系運算符

 

>=

 

大于等于

 

關系運算符

 

<=

 

小于等于

 

關系運算符

 

==

 

等于。用于判斷兩個值是否相等,如果是給變量賦值,請使用“”號

 

關系運算符

 

!=

 

不等于

 

關系運算符

 

A~B

 

判斷字符串A中是否包含能匹配B表達式的子字符串

 

關系運算符

 

A!~B

 

判斷字符串A中是否不包含能匹配B表達式的子字符串

 

正則表達式

 

/正則/

 

如果在"//"中可以寫入字符,也可以支持正則表達式

BEGIN

BEGIN是awk的保留字,是一種特殊的條件類型。BEGIN的執行時機是“在 awk程序一開始時,尚未讀取任何數據之前執行”。一旦BEGIN后的動作執行一次,當awk開始從文件中讀入數據,BEGIN的條件就不再成立,所以BEGIN定義的動作只能被執行一次。

例如:

[root@localhost ~]$ awk 'BEGIN{printf "This is a transcript n" } {printf $2 "t" $6 "n"}’ student.txt

#awk命令只要檢測不到完整的單引號不會執行,所以這個命令的換行不用加入“|”,就是一行命令

#這里定義了兩個動作

#第一個動作使用BEGIN條件,所以會在讀入文件數據前打印“這是一張成績單”(只會執行一次)

#第二個動作會打印文件的第二字段和第六字段

END

END也是awk保留字,不過剛好和BEGIN相反。END是在awk程序處理完所有數據,即將結束時執行。END后的動作只在程序結束時執行一次。例如:

[root@localhost ~]$ awk 'END{printf "The End n"} {printf $2 "t" $6 "n"}’ student.txt

#在輸出結尾輸入“The End”,這并不是文檔本身的內容,而且只會執行一次

關系運算符

舉幾個例子看看關系運算符。假設我想看看平均成績大于等于87分的學員是誰,就可以這樣輸入命令:

例子1:

[root@localhost ~]$ cat student.txt | grep -v Name | awk '$6 >= 87 {printf $2 "n"}'

#使用cat輸出文件內容,用grep取反包含“Name”的行

#判斷第六字段(平均成績)大于等于87分的行,如果判斷式成立,則打第六列(學員名$2)

加入了條件之后,只有條件成立動作才會執行,如果條件不滿足,則動作則不運行。通過這個實驗,大家可以發現,雖然awk是列提取命令,但是也要按行來讀入的。這個命令的執行過程是這樣的:

1)如果有BEGIN條件,則先執行BEGIN定義的動作。

2)如果沒有BEGIN條件,則讀入第一行,把第一行的數據依次賦予$0、$1、$2等變量。其中$0代表此行的整體數據,$1代表第一字段,$2代表第二字段。

3)依據條件類型判斷動作是否執行。如果條件符合,則執行動作,否則讀入下一行數據。如果沒有條件,則每行都執行動作。

4)讀入下一行數據,重復執行以上步驟。

再舉個例子,如果我想看看Sc用戶的平均成績呢:

例子2:

[root@localhost ~]$ awk '$2 ~ /AAA/ {printf $6 "n"}' student.txt

#如果第二字段中輸入包含有“Sc”字符,則打印第六字段數據

85.66

這里要注意在awk中,使用“//”包含的字符串,awk命令才會查找。也就是說字符串必須用“//”包含,awk命令才能正確識別。

正則表達式

如果要想讓awk 識別字符串,必須使用“//”包含,例如:

例子1:

[root@localhost ~]$ awk '/Liming/ {print}’student.txt

#打印Liming的成績

當使用df命令查看分區使用情況是,如果我只想查看真正的系統分區的使用狀況,而不想查看光盤和臨時分區的使用狀況,則可以:

例子2:

[root@localhost ~]$ df -h | awk '/sda[O-9]/ {printf $1 "t" $5 "n"}’

#查詢包含有sda數字的行,并打印第一字段和第五字段

1.2.5 awk 內置變量

 

awk內置變量

 

作用

 

$0

 

代表目前awk所讀入的整行數據。我們已知awk是一行一行讀入數據的,$0就代表當前讀入行的整行數據。

 

$n

 

代表目前讀入行的第n個字段。比如,

$1表示第1個字段(列),$

2表示第2個字段(列),如此類推

 

NF

 

當前行擁有的字段(列)總數。

 

NR

 

當前awk所處理的行,是總數據的第幾行。

 

FS

 

用戶定義分隔符。awk的默認分隔符是任何空格,如果想要使用其他分隔符(如“:”),就需要FS變量定義。

 

ARGC

 

命令行參數個數。

 

ARGV

 

命令行參數數組。

 

FNR

 

當前文件中的當前記錄數(對輸入文件起始為1)。

 

OFMT

 

數值的輸出格式(默認為%.6g)。

 

OFS

 

輸出字段的分隔符(默認為空格)。

 

ORS

 

輸出記錄分隔符(默認為換行符)。

 

RS

 

輸入記錄分隔符(默認為換行符)。

awk常用統計實例

1、打印文件的第一列(域) :

awk '{print $1}' filename

 

2、打印文件的前兩列(域) :

awk '{print $1,$2}' filename

 

3、打印完第一列,然后打印第二列 :

awk '{print $1 $2}' filename

 

4、打印文本文件的總行數 :

awk 'END{print NR}' filename

 

5、打印文本第一行 :

awk 'NR==1{print}' filename

 

6、打印文本第二行第一列 :

sed -n "2, 1p" filename | awk 'print $1'

 

1. 獲取第一列

ps -aux | grep watchdog | awk '{print $1}'

 

2. 獲取第一列,第二列,第三列

ps -aux | grep watchdog | awk '{print $1, $2, $3}'

 

3. 獲取第一行的第一列,第二列,第三列

ps -aux | grep watchdog | awk 'NR==1{print $1, $2, $3}'

 

4. 獲取行數NR

df -h | awk 'END{print NR}'

 

5. 獲取列數NF(這里是獲取最后一行的列數,注意每行的列數可能是不同的)

ps -aux | grep watchdog | awk 'END{print NF}'

 

6. 獲取最后一列

ps -aux | grep watchdog | awk '{print $NF}'

 

7. 對文件進行操作

awk '{print $1}' fileName

 

8. 指定分隔符(這里以:分割)

ps -aux | grep watchdog |awk -F':' '{print $1}'

 

9. 超出范圍不報錯

ps -aux | grep watchdog | awk '{print $100}'

 

[root@localhost ~]$ cat /etc/passwd | grep "/bin/bash" | awk '{FS=":"} {printf $1 "t" $3 "n"}’

#查詢可以登錄的用戶的用戶名和UID

這里“:”分隔符生效了,可是第一行卻沒有起作用,原來我們忘記了“BEGIN”條件,那么再來試試;

[root@localhost ~]$ cat /etc/passwd | grep "/bin/bash" | awk 'BEGIN {FS=":"} {printf $1 "t" $3 "n"}’

 

[root@localhost ~]$ cat /etc/passwd | grep "/bin/bash" | awk 'BEGIN {FS=":"} {printf $1 "t" $3 "t 行號:” NR "t 字段數:" NF "n"}’

#解釋下awk命令

#開始執行{分隔符是“:”}{輸出第一字段和第三字段輸出行號(NR值)字段數(NF值)}

root 0 行號:1 字段數:7

user1 501 行號:2 字段數:7

如果我只想看看sshd這個偽用戶的相關信息,則可以這樣使用:

[root@localhost ~]$ cat /etc/passwd | awk 'BEGIN {FS=":"} $1=="sshd" {printf $1 "t" $3 "t 行號:" NR "t 字段數:" NF "n"}’

#可以看到sshd 偽用戶的UID是74,是/etc/passwd_文件的第28行,此行有7個字段

1.2.6 awk 流程控制

我們再來利用下student.txt文件做個練習,后面的使用比較復雜,我們再看看這個文件的內容:

[root@localhost ~]$ cat student.txt

ID Name php Linux MySQL Average

1 AAA 66 66 66 66

2 BBB 77 77 77 77

3 CCC 88 88 88 88

我們先來看看該如何在awk中定義變量與調用變量的值。假設我想統計PHP成績的總分,那么就應該這樣:

[root@localhost ~]$ awk 'NR==2 {php1=$3}

NR==3 {php2=$3}

NR==4 {php3=$3;totle=phpl+php2+php3;print "totle php is " totle}’ student.txt

#統計PHIP成績的總分

我們解釋下這個命令。

"NR==2 {php1=$3}" (條件是NR==2,動作是php1=$3)這句話是指如果輸入數據是第二行(第一行是標題行),就把第二行的第三字段的值賦予變量"php1"。

"NR==3 {php2=$3}" 這句話是指如果輸入數據是第三行,就把第三行的第三字段的值賦予變量"php2"。

"NR==4 {php3=$3;totle=phpl+php2+php3;print "totle php is " totle}"("NR==4"是條件,后面{}中的都是動作)這句話是指如果輸入數據是第四行﹐就把第四行的第三字段的值賦予變量"php3";然后定義變量totle的值是"php1+php2+php3";然后輸出"totle php is"關鍵字,后面加變量totle的值。

在awk編程中,因為命令語句非常長,在輸入格式時需要注意以下內容:

l 多個條件 {動作} 可以用空格分割,也可以用回車分割。

l 在一個動作中,如果需要執行多個命令,需要用 “;” 分割,或用回車分割。

l 在awk中,變量的賦值與調用都不需要加入“$”符。

l 條件中判斷兩個值是否相同,請使用 “==”,以便和變量賦值進行區分。

在看看該如何實現流程控制,假設如果Linux成績大于90,就是一個好男人(學PHP的表示壓力很大!) :

[root@localhost ~]$ awk '{if (NR>=2) {if ($4>60) printf $2 "is a good man!n"}}’ student.txt

#程序中有兩個if判斷,第一個判斷行號大于2,第二個判斷Linux成績大于90分

Liming is a good man !

Sc is a good man !

1.2.7 awk 函數

awk編程也允許在編程時使用函數,我們講講awk的自定義函數。awk函數的定義方法如下:

function 函數名(參數列表){

函數體

}

我們定義一個簡單的函數,使用函數來打印student.txt的學員姓名和平均成績,應該這樣來寫函數:

[root@localhost ~]$ awk 'function test(a,b) { printf a "t" b "n"}

#定義函數test,包含兩個參數,函數體的內容是輸出這兩個參數的值

{ test($2,$6) } ' student.txt

#調用函數test,并向兩個參數傳遞值。

Name Average

AAA 87.66

BBB 85.66

CCC 91.66

1.2.8 awk 中調用腳本

對于小的單行程序來說,將腳本作為命令行自變量傳遞給awk是非常簡單的,而對于多行程序就比較難處理。當程序是多行的時候,使用外部腳本是很適合的。首先在外部文件中寫好腳本,然后可以使用awk的-f選項,使其讀入腳本并且執行。

例如,我們可以先編寫一個awk腳本:

[root@localhost ~]$ vi pass.awk

BEGIN {FS=":"}

{ print $1 "t" $3}

然后可以使用“一f”選項來調用這個腳本:

[root@localhost ~]$ awk -f pass.awk /etc/passwd

rooto

bin1

daemon2

…省略部分輸出…

1.3 sed 文本選取、替換、刪除、新增的命令

sed主要是用來將數據進行選取、替換、刪除、新增的命令。

語法:

[root@localhost ~]$ sed [選項] ‘[動作]’ 文件名

 

選項:

-n: 一般sed命令會把所有數據都輸出到屏幕,如果加入此選擇,則只會把經過sed命令處理的行輸出到屏幕。

-e: 允許對輸入數據應用多條sed命令編輯。

-f 腳本文件名: 從sed腳本中讀入sed操作。和awk命令的-f非常類似。

-r: 在sed中支持擴展正則表達式。

-i: 用sed的修改結果直接修改讀取數據的文件,而不是由屏幕輸出

 

動作:

num a : 追加,在當前行后添加一行或多行。添加多行時,除最后一行外,每行末尾需要用“”代表數據未完結。num表示第幾行

c : 行替換,用c后面的字符串替換原數據行,替換多行時,除最后一行外,每行末尾需用“”代表數據未完結。

num i : 插入,在當期行前插入一行或多行。插入多行時,除最后一行外,每行末尾需要用“”代表數據未完結。num表示第幾行

d ; 刪除,刪除指定的行。

p : 打印,輸出指定的行。

s : 字串替換,用一個字符串替換另外一個字符串。格式為“行范圍s/"舊字串/新字串/g”(和vim中的替換格式類似)。

對sed命令大家要注意,sed所做的修改并不會直接改變文件的內容(如果是用管道符接收的命令的輸出,這種情況連文件都沒有),而是把修改結果只顯示到屏幕上,除非使用“-i”選項才會直接修改文件。

2 字符處理命令

2.1 sort 排序命令

[root@localhost~]$ sort [選項] 文件名

選項:

 

-f: 忽略大小寫

-b: 忽略每行前面的空白部分

-n: 以數值型進行排序,默認使用字符串型排序

-r: 反向排序

-u: 刪除重復行。就是uniq命令

-t: 指定分隔符,默認是分隔符是制表符

-k n[,m]: ―按照指定的字段范圍排序。從第n字段開始,m字段結束(默認到行尾)

案例:

sort命令默認是用每行開頭第一個字符來進行排序的,比如:

[root@localhost~]$ sort /etc/passwd

#排序用戶信息文件

如果想要反向排序,請使用“-r”選項:

[root@localhost~]$ sort -r/etc/passwd

#反向排序

如果想要指定排序的字段,需要使用“-t”選項指定分隔符,并使用“-k”選項指定字段號。加入我想要按照UID字段排序/etc/passwd文件:

[root@localhost~]$ sort -t ":" -k 3,3 /etc/passwd

#指定分隔符是“:”,用第三字段開頭,第三字段結尾排序,就是只用第三字段排序

因為sort默認是按照字符排序,前面用戶的UID的第一個字符都是1,所以這么排序。要想按照數字排序,請使用“-n”選項:

[root@localhost~]$ sort -n -t ":" -k 3,3 /etc/passwd

當然“-k”選項可以直接使用“-k 3”,代表從第三字段到行尾都排序(第一個字符先排序,如果一致,第二個字符再排序,知道行尾)。

2.2 uniq 取消重復行

uniq [-c/d/D/u/i] [-f Fields] [-s N] [-w N] [InFile] [OutFile]

參數解釋:

-c: 在每列旁邊顯示該行重復出現的次數。

-d: 僅顯示重復出現的行列,顯示一行。

-D: 顯示所有重復出現的行列,有幾行顯示幾行。

-u: 僅顯示出一次的行列

-i: 忽略大小寫字符的不同

-f Fields: 忽略比較指定的列數。

-s N: 忽略比較前面的N個字符。

-w N: 對每行第N個字符以后的內容不作比較。

# uniq.txt

 

My name is Delav

My name is Delav

My name is Delav

I'm learning JAVA

I'm learning Java

I'm learning Java

who am i

Who am i

Python/ target=_blank class=infotextkey>Python is so simple

My name is Delav

That's good

That's good

And studying Golang

直接去重

uniq uniq.txt

結果為:

My name is Delav

I'm learning Java

who am i

Who am i

Python is so simple

My name is Delav

That's good

And studying Golang

顯示重復出現的次數

uniq -c uniq.txt 、

結果為:

3 My name is Delav

3 I'm learning Java

1 who am i

1 Who am i

1 Python is so simple

1 My name is Delav

2 That's good

1 And studying Golang

你會發現,上面有兩行 ”My name is Delav ” 是相同的。也就是說,當重復的行不相鄰時,uniq 命令是不起作用的。所以,經常需要跟

sort 命令一起使用。

sort uniq.txt | uniq -c

結果為:

1 And studying Golang

3 I'm learning Java

4 My name is Delav

1 Python is so simple

2 That's good

1 who am i

1 Who am i

只顯示重復的行,并顯示重復次數

uniq -cd uniq.txt

結果為:

3 My name is Delav

3 I'm learning Java

2 That's good

顯示所有重復的行,不能與 -c 一起使用

uniq -D uniq.txt

My name is Delav

My name is Delav

My name is Delav

I'm learning Java

I'm learning Java

I'm learning Java

That's good

That's good

忽略第幾列字符

下面這里 -f 1 忽略了第一列字符,所以"who am i" 和 "Who am i" 判定為重復

uniq -c -f 1 uniq.txt

結果為:

3 My name is Delav

3 I'm learning Java

2 who am i

1 Python is so simple

1 My name is Delav

2 That's good

1 And studying Golang

忽略大小寫

下面這里 -i 忽略了大小寫,所以"who am i" 和 "Who am i" 判定為重復

uniq -c -i uniq.txt

結果為:

3 My name is Delav

3 I'm learning Java

2 who am i

1 Python is so simple

1 My name is Delav

2 That's good

1 And studying Golang

忽略前面N個字符

下面這里 -s 4 表示忽略前面四個字符,所以"who am i" 和 "Who am i" 判定為重復

uniq -c -s 4 uniq.txt

結果為:

3 My name is Delav

3 I'm learning Java

2 who am i

1 Python is so simple

1 My name is Delav

2 That's good

1 And studying Golang

忽略第N個字符后的內容

uniq -c -w 2 uniq.txt

2.3 wc 統計命令

[root@localhost~]$ wc [選項] 文件名

選項:

-l:只統計行數

-w:只統計單詞數

-m:只統計字符數

分享到:
標簽:shell
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定