第九章、shell腳本編程基礎
第九章、shell腳本編程基礎
本章內容
- 編程基礎
- 腳本基本格式
- 變量
- 運算
- 條件測試
- 配置用戶環境
編程基礎
- 程序:指令+數據
- 程序編程風格:
過程式:以指令為中心,數據服務於指令
對象式:以數據為中心,指令服務於數據
- shell程序:提供了編程能力,解釋執行
程序的執行方式
- 計算機:運行二進制指令
- 編程語言:
低級:匯編
高級:
編譯:高級語言-->編譯器-->目標代碼
java,C#
解釋:高級語言-->解釋器-->機器代碼
shell, perl, python
(系統後臺有個解釋器,直接將語言轉化為機器碼,放到內存中直接運行)
編程基本概念
- 編程邏輯處理方式:
順序執行
循環執行
選擇執行
- shell編程:過程式、解釋執行
編程語言的基本結構:
各種系統命令的組合
數據存儲:變量、數組
表達式: a + b
語句:if
shell腳本基礎
- shell腳本:
包含一些命令或聲明,並符合一定格式的文本文件
- 格式要求:首行shebang機制
#!/bin/bash(告訴系統是哪種shell語法)
#!/usr/bin/python
#!/usr/bin/perl
- shell腳本的用途有:
自動化常用命令(三次命令以上,推薦使用腳本)
執行系統管理和故障排除
創建簡單的應用程序
處理文本或文件
創建shell腳本
- 第一步:使用文本編輯器來創建文本文件
第一行必須包括shell聲明序列:#!
#!/bin/bash
添加註釋
註釋以#開頭
- 第二步:運行腳本
給予執行權限,在命令行上指定腳本的絕對或相對路徑
直接運行解釋器,將腳本作為解釋器程序的參數運行
腳本規範
- 腳本代碼開頭約定
1、第一行一般為調用使用的語言
2、程序名,避免更改文件名為無法找到正確的文件
3、版本號
4、更改後的時間
5、作者相關信息
6、該程序的作用,及註意事項
7、最後是各版本的更新簡要說明
腳本的基本結構
- 腳本的基本結構
#!SHEBANG
CONFIGURATION_VARIABLES
FUNCTION_DEFINITIONS
MAIN_CODE
- shell腳本示例
#!/bin/bash
# ------------------------------------------
# Filename: hello.sh
# Revision: 1.1
# Date: 2017/11/22
# Author: sunan
# Email: [email protected]
# Website: www.sunanblog.com
# Description: This is the first script
# ------------------------------------------
# Copyright: 2017 sunan
# License: GPL
echo “hello shell”
腳本調試
- 檢測腳本中的語法錯誤
bash -n /path/to/some_script(檢查語法錯誤,不檢查命令錯誤)
- 調試執行
bash -x /path/to/some_script(檢查語法和命令錯誤)
變量
- 變量:命名的內存空間
數據存儲方式:
字符:
數值:整型,浮點型
- 變量:變量類型
作用:
1、數據存儲格式
2、參與的運算
3、表示的數據範圍
類型:
字符
數值:整型、浮點型
- 強類型:變量不經過強制轉換,它永遠是這個數據類型,不允許隱式的類型轉換。一般定義變量時必須指定類型、參與運算必須符合類型要求;調用未聲明變量會產生錯誤
如 java,c#
- 弱類型:語言的運行時會隱式做數據類型轉換。無須指定類型,默認均為字符型;參與運算會自動進行隱式類型轉換;變量無須事先定義可直接調用
如:bash 不支持浮點數,php
- 變量命名法則:
1、不能使程序中的保留字:例如if, for
2、只能使用數字、字母及下劃線,且不能以數字開頭
3、見名知義
4、統一命名規則:小駝峰命名法和大駝峰命名法
例如:firstFunctionName( )(小駝峰命名法)
FirstClassName( ) (大駝峰命名法)
bash中變量的種類
- 根據變量的生效範圍等標準劃分下面變量類型:
局部變量:生效範圍為當前shell進程;對當前shell之外的其它shell進程,包括當前shell的子shell進程均無效(如何查看當前的shell屬於哪個bash進程,見附錄1)
環境(全局)變量:生效範圍為當前shell進程及其子進程
本地變量:生效範圍為當前shell進程中某代碼片斷,通常指函數
位置變量:$1, $2, ...來表示,用於讓腳本在腳本代碼中調用通過命令行傳遞給它的參數
特殊變量:$?, $0, $*, $@, $#,$$
局部變量
- 變量賦值:name=‘value’(=兩邊不要加空格)
將變量賦兩遍值,不是將原來空間的值覆蓋,而是新開辟一個空間進行賦值,
變量指向新的空間值,而原來的空間閑置並被別的賦值覆蓋。(2.66)
- 可以使用引用value:
(1) 可以是直接字串; name=“root"
(2) 變量引用:name="$USER"
(3) 命令引用:name=`COMMAND` name=$(COMMAND)
- 變量引用:${name} $name
"":弱引用,其中的變量引用會被替換為變量值
‘‘:強引用,其中的變量引用不會被替換為變量值,而保持原字符串
- 顯示已定義的所有變量:set
- 刪除變量:unset name
環境變量
- 變量聲明、賦值:
export name=VALUE
declare -x name=VALUE
環境變量賦予的值可以傳遞給子進程,但子進程修改環境變量的值只能往下傳遞,不能影響父進程的值。(詳見附錄1.2)
- 變量引用:$name, ${name}(其中腳本中調用參數超過10使用${name},因為腳本中$10 =$1+0)
- 顯示所有環境變量:
env
printenv
export
declare -x
- 刪除變量:
unset name
- bash內建的環境變量:
?PATH
?SHELL
?USER
?UID
?HOME
?PWD
?SHLVL(查看shell嵌套深度,詳見附錄1.3)
?LANG
?HOSTNAME
?HISTSIZE
?_(下劃線,上一條命令的參數)
只讀和位置變量
- 只讀變量:只能聲明,但不能修改和刪除
聲明只讀變量:
readonly name
declare -r name
查看只讀變量:
readonly –p
- 位置變量:在腳本代碼中調用通過命令行傳遞給腳本的參數
$1, $2, ...:對應第1、第2等參數,shift [n]換位置(往前移動幾個位置,詳見1.6)
$0: 命令本身
$*: 傳遞給腳本的所有參數,全部參數合為一個字符串
$@: 傳遞給腳本的所有參數,每個參數為獨立字符串
$#: 傳遞給腳本的參數的個數
$@ $* 只在被雙引號包起來的時候才會有差異
set -- 清空所有位置變量
(4.10)
退出狀態
- 進程使用退出狀態來報告成功或失敗
0 代表成功,1-255代表失敗
- $? 變量保存最近的命令退出狀態
例如:
ping -c1 -W1 hostdown &> /dev/null
echo $?
退出狀態碼
- bash自定義退出狀態碼
exit [n]:自定義退出狀態碼
註意:腳本中一旦遇到exit命令,腳本會立即終止;終止退出狀態取決於exit命令後面的數字
註意:如果未給腳本指定退出狀態碼,整個腳本的退出狀態碼取決於腳本中執行的最後一條命令的狀態碼
算術運算
- bash中的算術運算:help let
+, -, *, /, %取模(取余), **(乘方)
實現算術運算:
(1) let var=算術表達式
(2) var=$[算術表達式]
(3) var=$((算術表達式))
(4) var=$(expr arg1 arg2 arg3 ...)(詳見1.9)
(5) declare –i var = 數值
(6) echo ‘算術表達式’ | bc
- 乘法符號有些場景中需要轉義,如*
- bash有內建的隨機數生成器:$RANDOM(0-32767)
echo $[$RANDOM%50] :0-49之間隨機數
賦值
- 增強型賦值:
+=, -=, *=, /=, %=
- let varOPERvalue
例如:let count+=3
自加3後自賦值
- 自增,自減:
let var+=1
let var++
let var-=1
let var--
邏輯運算
- true, false
1, 0
- 與:
1 與 1 = 1
1 與 0 = 0
0 與 1 = 0
0 與 0 = 0
- 或:
1 或 1 = 1
1 或 0 = 1
0 或 1 = 1
0 或 0 = 0
- 非:!
! 1 = 0
! 0 = 1
- 短路運算
短路與
第一個為0,結果必定為0
第一個為1,第二個必須要參與運算
短路或
第一個為1,結果必定為1
第一個為0,第二個必須要參與運算
- 異或:^
異或的兩個值,相同為假,不同為真
條件測試
- 判斷某需求是否滿足,需要由測試機制來實現
專用的測試表達式需要由測試命令輔助完成測試過程
- 評估布爾聲明,以便用在條件性執行中
若真,則返回0
若假,則返回1
- 測試命令:
test EXPRESSION
[ EXPRESSION ]
[[ EXPRESSION ]]
註意:EXPRESSION前後必須有空白字符
=~後正則表達式不要加引號
字符串匹配加引號
條件性的執行操作符
- 根據退出狀態而定,命令可以有條件地運行
&& 代表條件性的AND THEN
|| 代表條件性的OR ELSE
例如:
grep -q no_such_user /etc/passwd \
|| echo ‘No such user‘
No such user
ping -c1 -W2 station1 &> /dev/null \
> && echo "station1 is up" \
> || (echo ‘station1 is unreachable‘; exit 1)
station1 is up
test命令
- 長格式的例子:
test "$A" == "$B" && echo "Strings are equal"
test “$A” -eq “$B” && echo "Integers are equal"
- 簡寫格式的例子:
[ "$A" == "$B" ] && echo "Strings are equal"
[ "$A" -eq "$B" ] && echo "Integers are equal"
建議使用簡寫格式,註意[ 和單詞之間有空格。
[ ]裏面有東西就為真,但是要用” “把變量引起來才知道有東西。(詳見1.12)
bash的數值測試
- -v VAR
變量VAR是否設置(詳見附錄1.12)
- 數值測試:(判斷數字大小,兩邊必須都是數字)
-gt 是否大於
-ge 是否大於等於
-eq 是否等於
-ne 是否不等於
-lt 是否小於
-le 是否小於等於
bash的字符串測試
- 字符串測試:
== 是否等於
> ascii碼是否大於ascii碼
< 是否小於
!= 是否不等於
=~ 左側字符串是否能夠被右側的PATTERN(正則表達式)所匹配(左側能否包含右側)正則表達式中變量加引號,字符串不加引號。(詳見附錄1.13)
註意: 此表達式一般用於[[ ]]中;擴展的正則表達式
[[]]中判斷字符串是否相等用==,[]判斷字符串是否相等用一個=即可,==也行。這種判斷一般一個中括號就行了,兩個中括號用於支持正則表達式。
-z "STRING“ 字符串是否為空,空為真,不空為假
-n "STRING“ 字符串是否不空,不空為真,空為假(詳見附錄1.12)
註意:用於字符串比較時的用到的操作數都應該使用引號
Bash的文件測試
- 存在性測試
-a FILE:同-e
-e FILE: 文件存在性測試,存在為真,否則為假
- 存在性及類別測試
-b FILE:是否存在且為塊設備文件
-c FILE:是否存在且為字符設備文件
-d FILE:是否存在且為目錄文件
-f FILE:是否存在且為普通文件
-h FILE 或 -L FILE:存在且為符號鏈接文件(詳見附錄1.15)
-p FILE:是否存在且為命名管道文件
-S FILE:是否存在且為套接字文件
Bash的文件權限測試
- 文件權限測試:
-r FILE:是否存在且可讀
-w FILE: 是否存在且可寫
- -x FILE: 是否存在且可執行(詳見附錄1.16)
- 文件特殊權限測試:
-u FILE:是否存在且擁有suid權限
-g FILE:是否存在且擁有sgid權限
-k FILE:是否存在且擁有sticky權限
Bash的文件屬性測試
- 文件大小測試:
-s FILE: 是否存在且非空
- 文件是否打開:
-t fd: fd 文件描述符是否在某終端已經打開(詳見附錄1.14)
-N FILE:文件自從上一次被讀取之後是否被修改過
-O FILE:當前有效用戶是否為文件屬主
-G FILE:當前有效用戶是否為文件屬組
(當前有效用戶和實際用戶不一定是同一個人,像當前用戶執行passwd,當前實際執行的是root權限,當時有效用戶變成了root,實際用戶是當前用戶)
- 雙目測試:
FILE1 -ef FILE2: FILE1是否是FILE2的硬鏈接
FILE1 -nt FILE2: FILE1是否新於FILE2(mtime)
FILE1 -ot FILE2: FILE1是否舊於FILE2
Bash的組合測試條件
- 第一種方式:
COMMAND1 && COMMAND2 並且
COMMAND1 || COMMAND2 或者
! COMMAND 非
如:[[ -r FILE ]] && [[ -w FILE ]]
- 第二種方式:
EXPRESSION1 -a EXPRESSION2 並且
EXPRESSION1 -o EXPRESSION2 或者
! EXPRESSION
必須使用測試命令進行
示例:
[ -z “$HOSTNAME” -o $HOSTNAME "==\
"localhost.localdomain" ] && hostname www.magedu.com
[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
使用read命令來接受輸入
- 使用read來把輸入值分配給一個或多個shell變量
-p 指定要顯示的提示
-s 靜默輸入,一般用於密碼
-n N 指定輸入的字符長度N
-d ‘字符’ 輸入結束符
-t N TIMEOUT為N秒
read 從標準輸入中讀取值,給每個單詞分配一個變量
所有剩余單詞都被分配給最後一個變量
read -p “Enter a filename: “ FILE
bash如何展開命令行
(命令運行的過程)
- 把命令行分成單個命令詞
- 展開別名
(在腳本中別名不能使用)
- 展開大括號的聲明({})
echo {1..6}
1 2 3 4 5 6
- 展開波浪符聲明(~)
家目錄
- 命令替換$() 和 ``)
- 再次把命令行分成命令詞
- 展開文件通配(*、?、[abc]等等)
- 準備I/0重導向(<、>)
- 運行命令
上面的執行順序說明的執行的優先級
防止擴展
- 反斜線(\)會使隨後的字符按原意解釋
$ echo Your cost: \$5.00
$本身是表示變量的開始符,要原意顯示要加\
Your cost: $5.00
- 加引號來防止擴展
單引號(’)防止所有擴展
雙引號(”)也防止所有擴展,但是以下情況例外:
$(美元符號) - 變量擴展
`(反引號) - 命令替換
\(反斜線) - 禁止單個字符擴展
!(嘆號) - 歷史命令替換
bash的配置文件
- 按生效範圍劃分,存在兩類:
?全局配置:
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
? 個人配置:
~/.bash_profile
~/.bashrc
shell登錄兩種方式
- 交互式登錄:
(1)直接通過終端輸入賬號密碼登錄
(2)使用“su - UserName” 切換的用戶
執行順序:/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
- 非交互式登錄:
(1)su UserName
(2)圖形界面下打開的終端
(3)執行腳本
(4)任何其它的bash實例
執行順序: ~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh
上面的執行順序:在文件中調用的先後順序。
Profile類
- 按功能劃分,存在兩類:
profile類和bashrc類
- profile類:為交互式登錄的shell提供配置
全局:/etc/profile, /etc/profile.d/*.sh
個人:~/.bash_profile
功用:
(1) 用於定義環境變量
(2) 運行命令或腳本
Bashrc類
- bashrc類:為非交互式和交互式登錄的shell提供配置
全局:/etc/bashrc
個人:~/.bashrc
功用:
(1) 定義命令別名和函數
(2) 定義本地變量
編輯配置文件生效
- 修改profile和bashrc文件後需生效
兩種方法:
1重新啟動shell進程
2 . 或source
例:
. ~/.bashrc
執行腳本盡量不要使用.或source執行,因為會將原來bash中的相同變量值改變,而用bash或./filename會新開一個bash進程,執行完就退出,不會改變原來的變量值。
Bash 退出任務
- 保存在~/.bash_logout文件中(用戶)
- 在退出登錄shell時運行
- 用於
創建自動備份
清除臨時文件
可以在腳本寫上退出時要執行的操作。
上面的所有配置文件生效,都必須是需要用戶登錄,不登錄就無法讀取配置文件內容。要想不登錄執行,就要把文件寫入到開機啟動的內核中了。
$-變量
- h:hashall,打開這個選項後,Shell 會將命令所在的路徑hash下來,避免每次都要查詢。通過set +h將h選項關閉
- i:interactive-comments,包含這個選項說明當前的 shell 是一個交互式的 shell。所謂的交互式shell,在腳本中,i選項是關閉的。
- m:monitor,打開監控模式,就可以通過Job control來控制進程的停止、繼續,後臺或者前臺執行等。
- B:braceexpand,大括號擴展
- H:history,H選項打開,可以展開歷史列表中的命令,可以通過!感嘆號來完成,例如“!!”返回上最近的一個歷史命令,“!n”返回第 n 個歷史命令
- (詳見附錄1.18)
附錄:
1.1 進程樹
[root@centos7 ~]#ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 2058 0.0 0.2 147788 2360 ? Rs 08:14 0:04 sshd: root@pts/0
root 2062 0.0 0.2 116292 2796 pts/0 Ss 08:15 0:00 -bash
root 5191 0.0 0.0 107904 612 ? S 11:15 0:00 sleep 60
root 5198 0.0 0.1 151064 1804 pts/0 R+ 11:15 0:00 ps aux
……
查看所有的進程信息
[root@centos7 ~]#echo $$
2062
查看當前的進程編號
[root@centos7 ~]#pstree -p
├─smartd(591)
├─sshd(1013)───sshd(2058)───bash(2062)───pstree(5319)
├─systemd-journal(357)
├─systemd-logind(600)
查看當前的進程樹子進程和父進程信息,可以看到pstree是bash的子進程,運行pstree命令,會用bash程序會去解釋執行命令
[root@centos7 ~]#bash
[root@centos7 ~]#echo $$
5498
當前進程號
bash下面bash,bash的子進程bash
[root@centos7 ~]#echo $PPID
2062
查看父進程編號
[root@centos7 ~]#echo $$
2553
[root@centos7 ~]#exit
exit
[root@centos7 ~]#echo $$
2039
退出當前進程使用exit命令
[root@centos7 ~]#name=`cat /etc/issue`
[root@centos7 ~]#echo $name
The hostname is \n Time is \t TTY is \l \S Kernel \r on an \m
[root@centos7 ~]#echo "$name"
The hostname is \n
Time is \t
TTY is \l
\S
Kernel \r on an \m
變量是一個很長的文章,需要將變量加上雙引號才能按原格式輸出
1.2 環境變量
[root@centos7 ~]#export var=100
[root@centos7 ~]#echo $var
100
[root@centos7 ~]#bash
[root@centos7 ~]#echo $var
100
[root@centos7 ~]#var=200
[root@centos7 ~]#bash
[root@centos7 ~]#echo $var
200
[root@centos7 ~]#exit
exit
[root@centos7 ~]#exit
exit
[root@centos7 ~]#echo $var
100
可以看出環境變量的賦值只能向下傳遞,不能向上傳遞。
1.3 shell嵌套深度
[root@centos7 ~]#echo $SHLVL
1
[root@centos7 ~]#bash
[root@centos7 ~]#echo $SHLVL
2
[root@centos7 ~]#bash
[root@centos7 ~]#echo $SHLVL
3
查看shell的嵌套深度
1.4 ( )開啟新的bash
[root@centos7 ~]#( umask 066;touch /app/ff )
[root@centos7 ~]#umask
0022
[root@centos7 ~]#ls /app
binary ff passwd scripts
命令中的小括號代表新開一個bash,運行完命令後退出新開的bash。
1.5 scp傳文件
[root@centos7 ~]#scp filename [email protected]:
上傳文件到wang的家目錄中,密碼:magedu
[root@centos7 ~]#scp -r [email protected]:/home/wang/scripts /app/
將遠程主機上的文件拷貝到本機上,-r拷貝目錄
1.6 腳本中shift作用
[root@centos7 /app/scripts]#cat f1.sh
#!/bin/bash
echo "1st is $1"
echo "2st is $2"
echo "3st is $3"
shift
echo "1st is $1"
echo "2st is $2"
echo "3st is $3"
[root@centos7 /app/scripts]#./f1.sh a b c
1st is a
2st is b
3st is c
1st is b
2st is c
3st is
使用shift參數往左移動了一位
1.7 上傳文件腳本化
[root@centos7 /app/scripts]#vim scp14.sh
#!/bin/bash
scp $* [email protected]:
上傳代碼腳本化
1.8 腳本頭自動生成
#!/bin/bash
# create script header automatically
echo "#!/bin/bash
#Filename: $1
#Author: sunan
#Date: `date +%F`
">$1
chmod +x $1
vim + $1
[root@centos7 /app/scripts]#./make_script_header.sh news.sh
腳本頭腳本化
1.9 expr計算運算符加空格
[root@centos7 /app/scripts]#expr 1+2
1+2
[root@centos7 /app/scripts]#expr 1 + 2
3
[root@centos7 /app/scripts]#expr 1 * 2
expr: syntax error
[root@centos7 /app/scripts]#expr 1 \* 2
2
expr計算需要運算符加空格,*需要轉義。
[root@centos7 /app/scripts]#expr 1 - 1
0
[root@centos7 /app/scripts]#echo $?
1
[root@centos7 /app/scripts]#expr 1 - 1
0
[root@centos7 /app/scripts]#echo $?
1
[root@centos7 /app/scripts]#let 1-1
[root@centos7 /app/scripts]#echo $?
1
上面的命令可以正確執行,但返回的執行結果不是0,man expr可以看到:
Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION
is null or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.
1.10 字體加顏色
[root@centos7 /app/scripts]#vim color.sh
^[[31mred^[[0m
實現字體加顏色,其中的^[是在vim中使用Ctrl+v+[實現。
[root@centos7 /app/scripts]#cat color.sh
red
字體變成紅色
1.11 文件加顏色
[root@centos7 /app/scripts]#^Mcolor=$[RANDOM%7+31];echo -e "\033[${color}mred color\033[0m"
給文件加顏色
1.12 關於[ ]的判斷
[root@centos7 /app/scripts]#[ ]&& echo true || echo false
false
[root@centos7 /app/scripts]#[ 0 ]&& echo true || echo false
true
[root@centos7 /app/scripts]#[ "" ]&& echo true || echo false
false
[root@centos7 /app/scripts]#[ " " ]&& echo true || echo false
true
[root@centos7 /app/scripts]#a=111
[root@centos7 /app/scripts]#[ $a ]&& echo true || echo false
true
[root@centos7 /app/scripts]#unset a
[root@centos7 /app/scripts]#[ $a ]&& echo true || echo false
false
[root@centos7 /app/scripts]#a=" "
[root@centos7 /app/scripts]#[ $a ]&& echo true || echo false
false
[root@centos7 /app/scripts]#[ "$a" ]&& echo true || echo false
true
關於[ ]判斷執行成功條件
[root@centos7 ~]# var=hh;[ -n $var ]&&echo true || echo false
true
[root@centos7 ~]# unset var;[ -n $var ]&&echo true || echo false
true
[root@centos7 ~]# [ -n ]&&echo true || echo false
true
[root@centos7 ~]# [ -n "$var" ]&&echo true || echo false
false
當var沒有定義,但又沒加雙引號[ ]判斷相當於只有-n存在,就判斷為真。
中括號裏面當判斷的時候,要加雙引號。
[root@centos7 scripts]# vim useradd.sh
#!/bin/bash
[ $# -ne 1 ] &&echo -e "The arg must one \n Usage:useradd.sh username" && exit 10
id $1 &> /dev/null && echo "$! is exist " && exit 20
useradd $1 && echo "$! is created"
判斷用戶輸入的參數是否等於1,不是退出,是繼續下面的命令。
[root@centos7 scripts]# var="";[ -v var ]&&echo true ||echo false
true
[root@centos7 scripts]# var=ab;[ -v var ]&&echo true ||echo false
true
[root@centos7 scripts]# unset var;[ -v var ]&&echo true ||echo false
false
只要變量定義了就為真,var前面不需要加$,因為-v 的作用就是直接加var。
[root@centos7 scripts]# vim useradd.sh
#!/bin/bash
[ -n “$1”] ||{echo -e "The arg must one \n Usage:useradd.sh username" && exit 10;}
id $1 &> /dev/null && echo "$! is exist " && exit 20
useradd $1 && echo "$! is created"
-n 判斷$1是否為空,空就是假執行後面命令,非空為真,跳過後面命令執行下面命令。同時上面必須用{ },( )新開一個子shell,退出是退出一個子shell。
1.13關於[[ ]]的判斷
[root@centos7 ~]# filename=f1.sh;[[ "$filename" =~ \.sh$ ]] && echo true || echo false
true
[root@centos7 ~]# filename=f1.sh;[[ "$filename" =~ "\.sh$" ]] && echo true || echo false
false
和正則表達式做判斷時,字符串加引號被認為字符串和引號是一個整體。
[]:單中括號不支持正則表達式
[root@centos7 ~]# var="abc*";[[ "$var" == "abc*" ]]&&echo true ||echo false
true
[root@centos7 ~]# var="abc*";[[ "$var" == abc* ]]&&echo true ||echo false
true
[root@centos7 ~]# var="abcdef*";[[ "$var" == abc* ]]&&echo true ||echo false
true #把*當成通配符了
[root@centos7 ~]# var="abdef*";[[ "$var" == abc* ]]&&echo true ||echo false
false
工作中最好不要這樣用,掌握一個原則:只有用到正則表達式匹配用[[ ]],通常的匹配用[ ]即可,不然容易亂。
[root@centos7 ~]# ip=1.1.1.1;[[ "$ip" =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]&&echo true || echo false
true
[root@centos7 ~]# ip=1111.1.1.1;[[ "$ip" =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]&&echo true || echo false
false
判斷一個ip地址是否正確
[root@centos7 ~]#filename=f1.sh ; [ "$filename" =~ \.sh$ ] && echo true ||echo false
判斷後綴
[root@centos7 ~]#var=haha123 ; [[ "$var" =~ ^[0-9]+$ ]] && echo true || echo false
判斷數字
[root@centos7 ~]#var=0123 ; [[ "$var" =~ ^0*[1-9][0-9]*$ ]] && echo true || echo false
判斷正整數
[root@centos7 ~]#mobile=12800138000 ;[[ "$mobile" =~ ^1[3456789][0-9]{9}$ ]] && echo true || echo false
手機號
1.14 文件描述符
面試題:當前這個進程打開了多少個文件?
每打開一個文件就打開一個文件描述符,就是統計文件描述符的個數。
[root@centos7 scripts]# ls -l /proc/$$/fd
total 0
lrwx------. 1 root root 64 Nov 25 08:13 0 -> /dev/pts/0
lrwx------. 1 root root 64 Nov 25 08:13 1 -> /dev/pts/0
lrwx------. 1 root root 64 Nov 25 08:13 2 -> /dev/pts/0
lrwx------. 1 root root 64 Nov 25 10:30 255 -> /dev/pts/0
[root@centos7 scripts]# ls /proc/$$/fd | wc -l
4
[root@centos7 scripts]# ls -l /proc/$$/fd | wc -l
5
同時註意加 -l和不加結果不同
1.15 鏈接文件
[root@centos7 scripts]# [ -d /lib ] && echo true
true
[root@centos7 scripts]# [ -l /lib ] && echo true
-bash: [: -l: unary operator expected
[root@centos7 scripts]# [ -L /lib ] && echo true
true
判斷文件屬性,需要先判斷是不是鏈接文件,如果是鏈接文件判斷的文件屬性石,鏈接的原文件的屬性。
1.16 文件權限判斷
[root@centos7 scripts]# [ -r /etc/shadow ]&& echo true
true
[root@centos7 scripts]# [ -w /etc/shadow ]&& echo true
true
[root@centos7 scripts]# [ -x /etc/shadow ]&& echo true
[root@centos7 scripts]# ll /etc/shadow
----------. 1 root root 1197 Nov 7 17:43 /etc/shadow
判斷一個文件的權限不能只看表面的權限,要看實際的最終權限。
1.17 read
[root@centos7 scripts]# read
asdf
[root@centos7 scripts]# echo $REPLY
asdf
[root@centos7 scripts]# read name
abc
[root@centos7 scripts]# echo $name
abc
read沒有給變量,就賦給了REPLY。
[root@centos7 scripts]# read name age title
sunan 26 CTO
[root@centos7 scripts]# echo $name $age $title
sunan 26 CTO
賦予多個值,最好一個個賦值。
[root@centos7 scripts]# read -s -p "please input your password:" password
please input your password:[root@centos7 scripts]#
-s靜默模式輸入信息後看不到。
[root@localhost ~]#read -n 8 -p "please input your password:" passwd
please input your password:12345678[root@localhost ~]#
-n 規定最多輸入幾個字符,超過最多的字符數就自動退出。
1.18$-變量
[root@localhost ~]#echo $-
himBH
查看當前啟用的功能。
[root@localhost ~]#set +h
[root@localhost ~]#echo $-
imBH
去掉hash功能
[root@localhost ~]#hash
-bash: hash: hashing disabled
[root@localhost ~]#set -h
[root@localhost ~]#hash
hits command
1 /bin/cat
3 /bin/ls
set -h 恢復hash功能的使用
[root@localhost ~]#vim i.sh
#!/bin/bash
echo "$-"
[root@localhost ~]#bash i.sh
hB
在腳本中i功能是被禁用的,i交互式(像別名)。
[root@localhost ~]#echo {1..9}
1 2 3 4 5 6 7 8 9
B大括號擴展功能可以使用
練習:
不想讓別的用戶登錄:生成文件/etc/nologin
第九章、shell腳本編程基礎