1. 程式人生 > 實用技巧 >【shell】-shell知識

【shell】-shell知識

第1章 shell基本概述

1.1 什麼是shell

shell是一個命令直譯器,主要用來接收使用者的指令,進入驅動作業系統,或硬體。
Linux裡有很多種shell,例如:
Bourne Shell(/usr/bin/sh或/bin/sh)
Bourne Again Shell(/bin/bash)
C Shell(/usr/bin/csh)
K Shell(/usr/bin/ksh)
Shell for Root(/sbin/sh)

1.2 什麼是shell指令碼

shell指令碼就是把命令全部放在一起執行
shell腳本里可以包含若干個變數,迴圈,if判斷,for迴圈,函式等
特定的格式+特定的語法+系統的命令 = shell指令碼

1.3 shell可以實現什麼功能

1.Linux系統支援的命令,都可以用shell實現
2.系統優化指令碼,例如:優化SSH 修改埠號 配置yum源 關閉SElinux,時間同步,安裝常用軟體等操作
3.定時任務,例如每天定時備份資料庫的資料
4.日誌切割指令碼,定時切割日誌
5.服務啟動指令碼,二進位制安裝的服務沒有systemd,可以寫指令碼啟動
6.程式碼上線指令碼,將開發好的程式碼使用指令碼部署到web伺服器
7.zabbix自定義監控指令碼,使用指令碼獲取自定義的監控項的數值
8.跳板機指令碼,可以使用shell開發一個跳板機

1.4 學習shell的必備技能

1.熟練的VIM技能
2.熟練的Linux基礎命令使用
3.熟練的正則表示式和三劍客命令使用

1.5 學習shell的正確姿勢

1.知道自己要幹什麼,想要什麼效果
2.拿到需求先不要立刻寫指令碼,先用命令列實現,然後轉換成指令碼
3.先能看懂,然後模仿,然後會修改,最後能按照自己的需求編寫各種shell指令碼
4.思考,練習,總結 --> 思考,練習,總結

第2章 shell入門

2.1 shell書寫方式

1.shell指令碼名稱必須要有含義,切忌隨便起名,在公司裡容易被打。檔案字尾名最好以.sh結尾。
2.shell指令碼首行建議新增使用的直譯器,如:#!/bin/bash
3.最好給自己的指令碼加個註釋,註釋內容包含了指令碼建立時間,作者,以及指令碼作用等。
4.註釋儘量不要有中文
5.指令碼放在專門的目錄裡

舉例:

#!/bin/bash   	#! 是一個約定的標記,它告訴系統這個指令碼需要什麼直譯器來執行,即使用哪一種 Shell。
# Author:michaelni [email protected]	#作者名稱
# Create Time 2020/08/24	#建立日期
# Script Description: this is my 1st shell script. #指令碼描述

2.2 第一個shell指令碼

cat > hello.sh <<
#!/bin/bash
echo "hello world"
EOF

2.3 shell執行方式

2.3.1執行指令碼命令

./hello.sh
bash hello.sh
source hello.sh

2.3.2首行不指定直譯器

1.如果不在指令碼首行指定 #!/bin/bash直譯器,那麼./執行的時候系統會預設呼叫bash來執行指令碼。
2.那是如果我的指令碼是python語言寫的,那麼執行的使用就會報錯。

2.3.3首行指定直譯器

1.如果首行添加了直譯器./執行的時候預設會讀取指令碼第一行,來確定使用什麼直譯器執行指令碼。

2.3.4直接指定直譯器執行

我們也可以直接指定使用什麼直譯器來執行,那樣即使指令碼首行沒有新增直譯器也可以執行,例如
bash test.sh
python test.sh

2.3.5python的hello

#!/usr/bin/python3
hello = 'helloo'
print{hello}

第3章 shell變數

3.1什麼是變數

變數是Shell傳遞資料的一種方式。
以一個固定的字串去表示一個不固定的值,便於後續的複用和維護

3.2變數的分類

環境變數(全域性變數)  對整個系統生效
普通變數(區域性變數)  只對當前的指令碼生效

變數的生存週期
永久的 需要修改環境變數配置檔案 變數永久生效 /etc/profile
臨時的 直接使用export宣告變數即可,關閉shell則變數失效

臨時變數的export區別
不加export 則只對當前的shell生效
加export   則對當前開啟視窗所有的shell生效

3.3環境變數配置檔案生效的順序

1.登陸Shell首先會載入/etc/profile檔案
2.然後會執行家目錄中的環境變數配置檔案
3.按照執行順序
/etc/profile	
.bash_profile 
.bashrc
/etc/bashrc

3.4變數的命名規範

1.以大小寫字母 下劃線 數字 拼接成變數名,最好以字母開頭,最好名字有含義,不然寫著寫著很容易忘記這個變數幹嘛用的
2.變數名=變數值 等號表示給變數賦值,注意等號兩邊不要有空格
3.系統的環境變數都是大寫的,注意不要用系統保留的變數名稱,比如PATH
4.變數命名最好不要與系統命令衝突,比如 date=20200731

變數命名參考:

path_data   #全小寫
Path_Date   #駝峰寫法,首字母大寫
PATH_DATA	#全大寫

3.5變數定義的幾種方式

3.5.1字串定義變數

定義一個變數:

[root@m-61 ~]# name="michaelni"

檢視變數:

[root@m-01 ~]# echo "$name"
michaelni
[root@m-01 ~]# echo "${name}"
michaelni

3.5.2 命令定義變數

使用命令定義變數:

[root@m-01 ~]# time=`date`
[root@m-01 ~]# echo ${time}
[root@m-01 ~]# time=$(date +%F)
[root@m-01 ~]# echo ${time}

命令定義變數兩種方式區別:

1.反引號 `命令` 和 $(命令) 都可以表示將命令賦值給變數
2.建議使用$(),因為如果指令碼語句裡包含單引號和雙引號,很容易和反引號搞混,另外也不方便閱讀。

3.5.3 引用變數

引用變數$和 \({}的區別: [root@m01 ~]# echo "\)name_host"

[root@m01 ~]# echo "${name}_host"
nsthink_host

結論:

如果不加${},可能會造成歧義,使用${}更保險

單引號和雙引號區別:

[root@m01 ~]# echo "name is ${name}" 
name is nsthink
[root@m01 ~]# echo 'name is ${name}'
name is ${name}

結論:

1.單引號不會解析變數,給什麼,吐什麼
2.雙引號可以正確解析變數

什麼情況下使用單引號和雙引號:

1.如果需要解析變數,就用雙引號
2.如果輸出的結果要求是普通的字串,或者需要正確顯示特殊字元,則可以用單引號或者撬棍\

3.6 變數的傳遞

3.6.1位置引數傳遞

執行指令碼的時候我們可以通過傳遞引數來實現變數的賦值,接受引數的變數名是shell固定的,我們不能自定義.
指令碼如下:

cat > vars.sh <<'EOF'
#!/bin/bash
echo "#當前shell指令碼的檔名: $0"
echo "#第1個shell指令碼位置引數:$1"
echo "#第2個shell指令碼位置引數:$2"
echo "#第3個shell指令碼位置引數:$3"
echo "#所有傳遞的位置引數是: $*"
echo "#所有傳遞的位置引數是: $@"
echo "#總共傳遞的引數個數是: $#"
echo "#當前程式執行的 PID 是: $$"
echo "#上一個命令執行的返回結果: $?"
EOF

執行效果:

bash vars.sh 11 22 33 44            
#當前shell指令碼的檔名: vars.sh
#第1個shell指令碼位置引數:11
#第2個shell指令碼位置引數:22
#第3個shell指令碼位置引數:33
#所有傳遞的位置引數是: 11 22 33 44
#所有傳遞的位置引數是: 11 22 33 44
#總共傳遞的引數個數是: 4
#當前程式執行的 PID 是: 11943
#上一個命令執行的返回結果: 0

練習題:

1.編寫指令碼,通過變數傳參的形式免互動建立Linux系統使用者及密碼
2.編寫一個通過傳參自動修改主機名的指令碼

3.6.2互動式引數傳遞

[root@m01 ~]# cat read.sh
#!/bin/bash

#-s 不回顯,就是不顯示輸入的內容
#-n 指定字元個數
#-t 超時時間

read -p "Login: " user
read -s -t20 -p "Passwd: " passwd
echo -e "\n================="
echo -e "\nlogin: ${user} \npasswd: ${passwd}"

執行效果:

[root@m01 ~]# sh read.sh 
Login: root
Passwd: 
=================

login: root 
passwd: linux@123

練習題:

1.將前面練習的免互動建立使用者名稱密碼改寫為互動式指令碼
2.模擬Linux系統登陸介面
3.編寫一個備份指令碼,使用者傳遞2個引數,原目錄,目標目錄
4.編寫一個探測主機存活的指令碼,互動式的使用者輸入需要測試的IP地址,然後探測IP地址是否存活
5.編寫一個互動式修改主機名和IP地址的指令碼
6.編寫一個互動式的建立定時任務的指令碼,提示使用者輸入分 時 日 月 周和任務,例如:
*/5 * * * * /sbin/ntpdate time1.aliyun.com > /dev/null 2>&1 

3.7變數的運算

3.7.1什麼是變數運算

顧名思義,變數運算就是對變數的值進行運算,也就是 加 減 乘 除 取餘

3.7.2變數運算語法

expr 	   #只能做整數運算
$(()) 	   #雙括號運算,只支援整數運算,效率高
$[] 	   #整數運算,最簡潔
bc,awk 	   #支援小數點
%          #取餘

3.7.3舉例

expr

expr 10 + 10
expr 10 - 10
expr 10 * 10
expr 10 \* 10
expr 10 / 10 

num1=10
num2=20
expr ${num1} + ${num2}

$(( ))

echo $((10+10))
echo $((10-10))
echo $((10*10))
echo $((10/10))
echo $((10+10-5))
echo $((10+10-5*6))

num1=10
num2=20
echo $(($num1*$num2))

$[ ]

echo $[10+10]
echo $[10+10*20]
echo $[10+10*20-1000]
echo $[10+10*20/1000]

let

let a=10+10
echo $a

let a=10*10
echo $a    

let a=10/10
echo $a    

let a=$num1+$num2
echo $a

bc

echo 10*10|bc
echo 10*10.5|bc
echo 10-5.5|bc 
echo 10/5.5|bc

awk運算

awk 'BEGIN{print 10+10}'
awk 'BEGIN{print 10-10}'
awk 'BEGIN{print 10*10}'
awk 'BEGIN{print 10/10}'
awk 'BEGIN{print 10^10}'
awk 'BEGIN{print 10-4.5}'
awk 'BEGIN{print 10*4.5}'
awk 'BEGIN{print 10/4.5}'

3.7.4 練習題

練習題1:根據系統時間打印出今年和明年時間

[root@m01 ~]# echo "this year is $(date +%Y)"
this year is 2020
[root@m01 ~]# echo "this year is $(( $(date +%Y) + 1 ))" 
this year is 2021

練習題2:根據系統時間獲取今年還剩下多少星期,已經過了多少星期

[root@m01 ~]# date +%j
214
[root@m01 ~]# date +%U
30
[root@m01 ~]# echo "今年已經過了 $(date +%j) days"
今年已經過了 214 days
[root@m01 ~]# echo "今年還剩 $(( ( 365 - $(date +%j) ) / 7 )) 周"  
今年還剩 21 周
[root@m01 ~]# echo "今年還剩 $(( ( (365 / 7) - $(date +%U)) )) 周"
今年還剩 22 周

練習題3:完成簡單計算功能,通過read方式傳入2個值,進行加減乘除

[root@m01 ~]# cat vars-2.sh 
#!/bin/bash

read -p "請輸入要計算的第一個數字: " num1
read -p "請輸入要計算的第二個數字: " num2

echo "$num1 + $num2 = $(( $num1 + $num2 ))"
echo "$num1 - $num2 = $(( $num1 - $num2 ))"
echo "$num1 * $num2 = $(( $num1 * $num2 ))"
echo "$num1 / $num2 = $(( $num1 / $num2 ))"

3.7.5 作業

概念解釋:

1.簡單介紹shell指令碼是什麼,使用場景有哪些?
2.shell指令碼的書寫規範是什麼?
3.shell指令碼變數的定義方式有幾種?
4.shell指令碼如何引用變數?
5.shell指令碼特殊變數的意思是什麼?$0 $1 $2 $* $@ $# $$ $?
6.變數的運算方式

練習題:

0.今天課上的練習題自己全部寫一遍
1.使用Shell指令碼列印,系統版本、核心版本平臺、主機名、eth0網絡卡IP地址、lo網絡卡IP地址、當前主機的外網IP地址,提醒:curl icanhazip.com
2.看誰能用最精簡的指令碼實現一個計算器
3.檢視當前記憶體使用的百分比和系統已使用磁碟的百分比

拓展:

1.如何建立shell指令碼的時候自動把#!/bin/bash和註釋內容加上去
2.如何讓shell指令碼的輸出改變顏色
3.思考今天所寫的指令碼邏輯判斷是否嚴謹

第4章 條件判斷

4.1基於檔案進行判斷

4.1.1引數說明

4.1.2語法

第一種寫法

test -f /etc/passwd && echo "true" || echo "false"

第二種寫法

[ -f /etc/passwdd ] && echo "true" || echo "false"

4.1.3練習

[root@m01 ~]# [ -f /etc/passwd ] && echo "檔案存在" || echo "檔案不存在"
檔案存在
[root@m01:~]# [ -e /etc/passwd ] && echo "檔案存在" || echo "檔案不存在"
檔案存在
[root@m01:~]# [ -r /etc/passwd ] && echo "檔案可讀" || echo "檔案不可讀"
檔案可讀
[root@m01:~]# [ -x /etc/passwd ] && echo "檔案可執行" || echo "檔案不可執行"
檔案不可執行
[root@m01:~]# [ -s /dev/zero ] && echo "true"||echo "false"
false
[root@m01:~]# [ -s /dev/null ] && echo "true"||echo "false"
false
[root@m01:~]# [ -s /etc/passwd ] && echo "true"||echo "false"
true
[root@m01:~]# [ -f /dev/zero ] && echo "true"||echo "false"
false
[root@m01:~]# [ -f /dev/null ] && echo "true"||echo "false"
false
[root@m01:~]# [ -f /etc/passwd ] && echo "true"||echo "false"
true

4.2 基於整數進行判斷

4.2.1引數說明

4.2.2練習

單個條件

source /etc/init.d/functions 
[ 1 -eq 2 ] && action OK /bin/true || action NO /bin/false
[ 1 -ne 2 ] && action OK /bin/true || action NO /bin/false
[ 1 -gt 2 ] && action OK /bin/true || action NO /bin/false
[ 1 -lt 2 ] && action OK /bin/true || action NO /bin/false
[ 1 -ge 2 ] && action OK /bin/true || action NO /bin/false
[ 1 -le 2 ] && action OK /bin/true || action NO /bin/false

多個條件

[ 1 -eq 1 -a 2 -gt 1 ] && action OK /bin/true || action NO /bin/false
[ 1 -eq 1 -o 2 -gt 2 ] && action OK /bin/true || action NO /bin/false