shell程式設計基礎進階
為什麼學習shell程式設計
shell指令碼語言是實現linux/unix 系統管理機自動化運維所必備的重要工具,linux/unix系統的底層及基礎應用軟體的核心大部分涉及shell指令碼的內容。每一個合格的linux系統管理員或運維工程師,都需要熟練的編寫shell指令碼語言,並能夠閱讀系統及各類軟體附帶的shell指令碼內容
什麼是shell
shell是一個命令直譯器,它在作業系統的最外層,負責直接與使用者對話,把使用者的輸入解釋給作業系統,並處理各種各樣的作業系統的輸出結果,輸出到螢幕返回給使用者,這種對話方式可以是互動式(從鍵盤輸入命令,可以立即得到shell的迴應),或非互動(執行指令碼程式)的方式
shell種類
互動式shell
非互動式shell
登入式shell
/etc/profile -> /etc/profile.d/*.sh -> ~/.bash_profile -> ~/.bashrc -> /etc/bashrc
非登入式shell
~/.bashrc -> /etc/bashrc
shell執行方式
1、 bash script-name或 sh script-name (生成一個子shell執行)
2、 path/script-name或./script-name(新增執行許可權執行,預設根據指令碼第一行指定的直譯器執行,如果沒有指定則以當前預設shell直譯器執行)
3、 source script-name或.script-name(以當前預設shell直譯器執行)
4、cat script-name |bash
子shell
子shell的本質是shell的子程序
子程序是由父程序的概念引申而來,在linux系統下,我們所執行的應用程式幾乎都是從init(systemd)(pid為1的程序)程序延伸出來的,所以這些應用程式都視為init程序的子程序,而init則為它們的父程序
shell子程序是從一個父shell程序呼叫shell程式而產生的一個全新的shell,我們將這種全新的shell統稱為這個父shell的子shell
產生子shell的情況
1、在父shell中執行一個shell指令碼
bash ,執行環境不同,不能直接引用父shell變數,需export,定義的變數不能被父shell引用
2、在父shell中執行一條命令,在命令的末尾加上&
&,執行環境相同,直接引用父shell變數,定義的變數不能被父shell引用
STR0='123';STR0='abc' &
echo $STR0
3、在父shell中執行一條命令,使用() 中執行
(),執行環境相同,直接引用父shell變數,定義的變數不能被父shell引用
[root@web01 shell_class_03]# STR2='123' && (STR2='abc') && echo $STR2
123
4、在父shell中執行帶管道的命令
管道,執行環境相同,直接引用父shell變數,定義的變數不能被父shell引用
[root@web01 shell_class_03]# STR1='123';echo 111 |STR1='ABC';echo $STR1
123
shell應用場景
- 系統基礎配置
- 部署應用服務
- 配置應用服務
- 部署業務程式碼
- 應用服務備份
- 日誌分析
- 監控應用服務
shell基礎
- 命令補全和檔案路徑補全, 如果寫錯無法補全table
- 命令歷史記憶功能 history
- 別名功能 alias、unalias
- 常用快捷鍵 ctrl+u,k,a,e,l,c,z,d,r
- 前後臺作業控制 bg,fg,jobs,screen
- 輸入輸出重定向 > >> 2> 2>> < << &> cat
- |將前者命令的標準輸出交給後者命令的輸入
- |&將前者命令的錯誤輸出交給後者命令的輸入
- 命令之間的關係; 沒有邏輯關係,無論分號前面的命令執行是否成功都執行後者命令&&前面執行成功, 則執行後者||前面執行不成功, 則執行後者
shell萬用字元
- 匹配任意多個字元
? 匹配任意一個字元
[] 匹配括號中任意一個字元a-z,0-9,A-Z,a-Z
() 在子 shell 中執行(cd /boot;ls) (umask 077; touch file1000)
{}集合 touch file{1..9}
\轉義符
shell模式匹配
使用shopt 內建命令啟用shell選項 (extglob) 則會識別幾個擴充套件模式匹配運算子。
模式列表是由 | 分割
檢視shell選項 extglob
shopt |grep extglob
啟動shell選項 extglob
shopt -s extglob
關閉shell選項 extglob
shopt -u extglob
** 模式 ** | ** 說明 ** |
---|---|
?(pattern-list) | 匹配給定模式零或一次 |
*(pattern-list) | 匹配給定模式零次或多次 |
+(pattern-list) | 匹配給定模式一次或多次 |
@(pattern-list) | 匹配給定模式之一 |
!(pattern-list) | 匹配除了給定的模式 |
[root@mycentos6-clone ~]# ll total 0 -rw-r--r-- 1 root root 0 Nov1 07:02 123 -rw-r--r-- 1 root root 0 Nov1 07:02 aaaac -rw-r--r-- 1 root root 0 Nov1 06:51 aaab -rw-r--r-- 1 root root 0 Nov1 07:02 aad -rw-r--r-- 1 root root 0 Nov1 07:02 aadg -rw-r--r-- 1 root root 0 Nov1 07:02 bb -rw-r--r-- 1 root root 0 Nov1 07:02 c [root@mycentos6-clone ~]# ls !(c|bb|123) aaaacaaabaadaadg [root@mycentos6-clone ~]# rm !(c|bb|123) -f [root@mycentos6-clone ~]# ll total 0 -rw-r--r-- 1 root root 0 Nov1 07:02 123 -rw-r--r-- 1 root root 0 Nov1 07:02 bb -rw-r--r-- 1 root root 0 Nov1 07:02 c
單引號-雙引號-沒有引號
引號和不加引號的區別1
[root@zeqtx ~]# touch a b [root@zeqtx ~]# ll total 0 -rw-r--r--. 1 root root 0 Jun 25 16:25 a -rw-r--r--. 1 root root 0 Jun 25 16:25 b [root@zeqtx ~]# touch "a b" [root@zeqtx ~]# ll total 0 -rw-r--r--. 1 root root 0 Jun 25 16:25 a -rw-r--r--. 1 root root 0 Jun 25 16:25 a b -rw-r--r--. 1 root root 0 Jun 25 16:25 b
引號和不加引號的區別2:
[root@zeq36 tmp]# ll 總用量 0 -rw-r--r-- 1 root root 0 6月25 19:36 ? -rw-r--r-- 1 root root 0 6月25 19:32 * -rw-r--r-- 1 root root 0 6月25 19:33 aa -rw-r--r-- 1 root root 0 6月25 19:33 abc -rw-r--r-- 1 root root 0 6月25 19:33 b [root@zeq36 tmp]# ll ? -rw-r--r-- 1 root root 0 6月25 19:36 ? -rw-r--r-- 1 root root 0 6月25 19:32 * -rw-r--r-- 1 root root 0 6月25 19:33 b [root@zeq36 tmp]# ll "?" -rw-r--r-- 1 root root 0 6月25 19:36 ? [root@zeq36 tmp]# ll * -rw-r--r-- 1 root root 0 6月25 19:36 ? -rw-r--r-- 1 root root 0 6月25 19:32 * -rw-r--r-- 1 root root 0 6月25 19:33 aa -rw-r--r-- 1 root root 0 6月25 19:33 abc -rw-r--r-- 1 root root 0 6月25 19:33 b [root@zeq36 tmp]# ll "*" -rw-r--r-- 1 root root 0 6月25 19:32 *
雙引號和單引號區別1:
關於$
[root@zeqtx ~]# echo "$LANG" en_US.UTF-8 [root@zeqtx ~]# echo '$LANG' $LANG
雙引號和單引號區別2:
關於``
[root@zeqtx ~]# echo "`which awk`" /bin/awk [root@zeqtx ~]# echo '`which awk`' `which awk`
雙引號和單引號區別3:
關於!
[root@zeqtx ~]# echo '!ll' !ll [root@zeqtx ~]# echo "!ll" echo "ll /bin/awk " ll /bin/awk
shell常用命令與工具
cat
cat<<-EOF 1.[install lamp] 2.[install lnmp] 3.[exit] EOF
cat >> /etc/profile <<'EOF' $PATH EOF
read
格式:
read [options] varible1 varible2 ...
引數:
-p 顯示提示資訊
-t超時時間
-s取消回顯
-u繫結檔案描述符作為輸入
-a後跟一個變數,該變數會被認為是個陣列,然後給其賦值,預設是以空格為分割符
eval
- 執行引數做為shell命令
[root@VM_153_209_centos ~]# echo $a 3 [root@VM_153_209_centos ~]# echo $b stu [root@VM_153_209_centos ~]# eval echo ${b}{1..$a} stu1 stu2 stu3
tee
- 從標準輸入讀取寫到出和檔案
- -a 追加到檔案
printf
a=1 b=3 printf "%.2f" `echo "scale=2;$a/$b"|bc`
:
空命令
echo
字型顏色
echo -e "\033[30m 黑色字zeq trainning \033[0m" echo -e "\033[31m 紅色字zeq trainning \033[0m" echo -e "\033[32m 綠色字zeq trainning \033[0m" echo -e "\033[33m 黃色字zeq trainning \033[0m" echo -e "\033[34m 藍色字zeq trainning \033[0m" echo -e "\033[35m 紫色字zeq trainning \033[0m" echo -e "\033[36m 天藍字zeq trainning \033[0m" echo -e "\033[37m 白色字zeq trainning \033[0m"
背景顏色
echo -e "\033[40;37m 黑底白字 welcome to old1boy\033[0m" echo -e "\033[41;37m 紅底白字 welcome to old2boy\033[0m" echo -e "\033[42;37m 綠底白字 welcome to old3boy\033[0m" echo -e "\033[43;37m 黃底白字 welcome to old4boy\033[0m" echo -e "\033[44;37m 藍底白字 welcome to old5boy\033[0m" echo -e "\033[45;37m 紫底白字 welcome to old6boy\033[0m" echo -e "\033[46;37m 天藍白字 welcome to old7boy\033[0m" echo -e "\033[47;30m 白底黑字 welcome to old8boy\033[0m"
trap
trap [-lp] [ [引數] 訊號 ...]
引數 : shell命令
訊號
HUP(1) 掛起,通常因終端掉線或使用者退出而引發
INT(2)中斷,通常因按下Ctrl+C組合鍵而引發
QUIT(3)退出,通常因按下Ctrl+組合鍵而引發
ABRT(6)中止,通常因某些嚴重的執行錯誤而引發
ALRM(14)報警,通常用來處理超時
TERM(15)終止,通常在系統關機時傳送
SIGTSTP停止程序終端來的停止訊號
trap ':' INT EXIT TSTP TERM HUP
ofollow,noindex" target="_blank">jumpserver.sh
#!/bin/bash LB02=10.0.0.6 WEB01=10.0.0.7 menu(){ cat<< EOF 1) LB02 2) WEB01 6) h EOF } while true do trap ':' INT TSTP TERM HUP menu read -p "please input hostname num: " NUM case $NUM in 1|LB02) ssh root@$LB02 ;; 2|WEB01) ssh root@$WEB01 ;; h) menu ;; exec) exit 1 ;; esac done
expect
#!/usr/bin/expect set ip 10.0.0.6 set user root set password 123456 set timeout 5 spawn ssh $user@$ip expect { "yes/no" { send "yes\r"; exp_continue } "password:" { send "$password\r" }; } #互動方式 interact
expect-copy-sshkey.exp
#!/usr/bin/expect if { $argc != 1 } { send_user "usage: expect expect-copy-sshkey.exp host \n" exit } #define var set host [lindex $argv 0] set password "123456" spawn ssh-copy-id -i /home/oldgirl/.ssh/id_dsa.pub "oldgirl@$host" #spawn ssh -p 50718 disdata@$host /sbin/ifconfig set timeout 60 expect { -timeout 20 "yes/no"{ send "yes\r";exp_continue } "*password" { send "$password\r" } timeout{ puts "expect connect timeout,pls contact zeq."; return } } expect eof exit -onexit { send_user "zeq say good bye to you!\n" }
#!/bin/sh . /etc/init.d/functions [ ! -f iplist ] && echo "hostlists.txt is not exist." && exit 1 for host in `cat /home/oldgirl/iplist` do expect expect-copy-sshkey.exp $host &>/dev/null if [ $? -eq 0 ];then action "$host dis data" /bin/true else action "$host dis data" /bin/false fi done
mkpasswd openssl
mkpasswd -l 10 -c 3 -C 3 -d 3 openssl rand -base64 80
basename dirname
basename /etc/init.d/network network dirname /etc/init.d/network
/etc/init.d
shell指令碼
指令碼第一行
指定指令碼直譯器
#!/bin/sh #!/bin/bash #! /usr/bin/awk #! /bin/sed #! /usr/bin/tclsh #! /usr/bin/expect #! /usr/bin/perl #! /usr/bin/env python
指令碼註釋
單行註釋 #
多行註釋
<<'EOF' 語句1 語句2 ... 語句n EOF
指令碼構成
主指令碼
模組(子指令碼)
- 主指令碼 呼叫模組
- 模組中 有函式
- 先呼叫模組,再呼叫函式
指令碼執行引數
- -x將執行的指令碼內容及輸出顯示到螢幕上
- -n 不會執行該指令碼,僅查詢指令碼語法是否有問題,並給出錯誤提示。
- -v在執行指令碼時,先將指令碼的內容輸出到螢幕上然後執行指令碼,如果有錯誤,也會給出錯誤提示
變數
變數型別
自定義變數
1.定義變數變數名=變數值 ,不允許數字命名, 不能使用橫崗命名
2.引用變數$變數名 或 ${變數名}
3.檢視變數echo $變數名 set顯示所有變數,包括自定義變數和環境變數
4.取消變數unset 變數名 作用範圍:僅在當前 shell 中有效
系統環境變數
1.定義環境變數 export export 變數 ,將自定義變數轉換成環境變數
2.引用環境變數 $變數名 或 ${變數名}
3.檢視環境變數 echo $變數名 env |grep Name
4.取消環境變數 unset 變數名
5.作用範圍在當前shell和子shell有效
位置引數變數
$1
$2
$3
${10}
預先定義變數
$0 指令碼檔名
$* 所有的引數
$@所有的引數
set"I am" handsome zeq for i in "$*" ; do echo $i; done for i in "$@" ; do echo $i; done
$# 引數的個數
$$當前程序的 PID
$! 上一個後臺程序的 PID
$? 上一個命令的返回值 0 表示成功
$_在此之前執行的命令或指令碼的最後一個引數
變數賦值方式
1.顯式賦值(變數名=變數值)
2.read從鍵盤讀入變數值
read -p "請輸入數字:" echo $REPLY
3.定義或引用變數時注意事項: " "弱引用 ' '強引用
4.``命令替換等價於$()反引號中的shell命令會被先執行
變數子串
變數長度
${#string}
從前往後刪除變數內容
${string#substring} 從變數$string開頭開始刪除最短匹配$substring子串 ${string##substring} 從變數$string開頭開始刪除最長匹配$substring子串
從後往前刪除變數內容
${string%substring} 從變數$string結尾開始刪除最短匹配$substring子串 ${string%%substring} 從變數$string結尾開始刪除最長匹配$substring子串
索引及切片
${string:position} 在$string中,從$position個開始提取子串(從0開始計數) ${string:position:length} 在$string中,從位置$position之後開始提取長度為$length的子串
變數內容替換
${parameter/pattern/string} 使用string代替第一個匹配的pattern ${parameter//pattern/string} 使用string代替所有的pattern ${parameter/#pattern/string} 從開頭匹配string變數中的pattern, 用string替換匹配的pattern ${parameter/%pattern/string} 從結尾匹配string變數中的pattern, 用string替換匹配的pattern
變數替代
${value:-word} 如果變數名存在且非null,則返回變數的值。否則,返回word字串 用途:如果變數未定義,則返回備用的值 ${value:=word} 如果變數名存在且非null,則返回變數值。否則,設定這個變數值為word 並返回其值 用途:如果變數未定義,則設定變數為預設值,並返回預設值 ${value:?"not defined"} 如果變數名存在且非null,則返回變數的值。否則顯示變數名:message, 並退出當前的命令或者指令碼 用途:用於捕捉由於變數未定義而導致的錯誤,並退出程式 ${value:+word} 如果變數名存在且非null,則返回word。 否則返回null 用途:測試變數是否存在
變數作用域
環境變數
使用 export 定義,在當前shell及其子shell中生效
本地變數
僅在當前shell中生效
區域性變數
使用 local 定義 ,僅在函式中生效
表示式
運算子
++ -- 自增 自減
-
! ~ 正號 負號 邏輯取反 按位取反
/% 乘除取餘
-
-
加減
<<=>>= 比較符號
==!= 等於不等於
<<>> 左移右移
&|^ 按位與按位或按位異或
&&||邏輯與邏輯或
=+=-=*=/=%=&=|=^=<<=>>=各種賦值運算子
**冪運算
-
算術運算(整數)
** [] test** | ** (())[[]]** |
---|---|
-eq | ==或 = |
-ne | != |
-gt | > |
-ge | >= |
-lt | < |
-le | <= |
自增/自減
ping.sh" rel="nofollow,noindex" target="_blank">ping.sh#!/bin/bash IP=223.5.5.5 i=1 while((i<=4)) do if ping $IP -c 1 &> /dev/null;then echo "ping $IP is ok!" else echo "ping $IP is faild..." fi let i++ done
表示式符號
[ ]
[[ ]]
(( )) 僅用於整數
((1<2&&1>3)) ((1<2||1>3))
算術運算-bc
https://www.gnu.org/software/bc/manual/html_mono/bc.html
# a=1.2 # b=3 # echo "$a<$b" |bc 1 # echo "$a>$b" |bc 0 # echo "$a+$b" |bc 4.2 # x=$(echo "$a+$b" |bc) # echo $x 4.2
[root@VM_153_209_centos scripts]# a=9.8 [root@VM_153_209_centos scripts]# b=10.1 [root@VM_153_209_centos scripts]# echo "$a>$b" |bc 0 [root@VM_153_209_centos scripts]# echo "$a<$b" |bc 1
cat test.bc #!/bin/bc 1+2 quit
bc -q test.bc 3
#!/bin/bc array[1]=1 array[2]=2 array[1]+array[2] quit
bc -q test.bc 3
邏輯運算
** [] test ** | ** [[]] ** | ** 說明 ** |
---|---|---|
-a | && | and 與 |
-o | || | or 或 |
! | ! | not 非 |
字串運算
-z "str" 若串長度為0則真,-z 可以理解為zero -n "str"若串長度不為0則真,-n可以理解為no zero "str1"="str2" 若串1等於串2則真,可以使用"==" 代替"=" "str1"!="str2" 若串1不等於串2則真 "str1" =~ "pattern" 字串匹配成功則為真 [[ ]]
檔案測試
[ -f 檔案 ] 檔案存在且為普通檔案則真,條件表示式成立 [ -d 目錄 ] 目錄存在且為目錄檔案則真,條件表示式成立 [ -s 檔案 ] 檔案存在且檔案大小不為0則真,條件表示式成立 [ -e 檔案 ] 檔案存在則真,只要有檔案就行 [ -r 檔案 ] 檔案存在且可讀則真,條件表示式成立 [ -w 檔案 ] 檔案存在且可寫則真,條件表示式成立 [ -L 檔案 ] 檔案存在且為連結檔案則真,條件表示式成立 [ f1 -nt f2 ] 檔案f1比檔案f2新則真,條件表示式成立 [ f1 -ot f2 ] 檔案f1比檔案f2舊則真,條件表示式成立
流程控制
順序 選擇 迴圈
條件表示式
- 條件表示式的值只有真(非0 | 非空 | 條件成立 | $?為0(此條shell特有))、假(0 | 空 | 條件不成立 | $?不為0(此條shell特有))此規則適用於所有的計算機高階語言
算術運算
邏輯運算
Linux命令
選擇(分支)
if
if 條件表示式;then 命令 fi
#/bin/bash http="ss -lntup|grep nginx &> /dev/null" if eval $http then echo 1 else echo 0 fi
流程圖
st=>start: Start op=>operation: 命令1 cond=>condition: 條件表示式為真? e=>end st->cond cond(yes)->op->e cond(no)->e
if else
if 條件表示式;then 命令1 else 命令2 fi
st=>start: Start op=>operation: 命令1 op2=>operation: 命令2 cond=>condition: 條件表示式為真? e=>end st->cond cond(yes)->op->e cond(no)->op2->e
if elif else
if 條件表示式;then 命令1 elif 條件表示式2;then 命令2 else 命令3 fi
st=>start: Start op=>operation: 命令1 op2=>operation: 命令2 op3=>operation: 命令3 cond=>condition: 條件表示式為真? cond2=>condition: 條件表示式2為真? e=>end st->cond cond(yes)->op->e cond(no)->cond2 cond2(yes)->op2->e cond2(no)->op3->e
case
case 模式名 in 模式1) 命令1 ;; 模式2) 命令2 ;; 模式3) 命令3 ;; *) 其它命令 esac
st=>start: Start io=>inputoutput: 模式名 op=>operation: 命令1 op2=>operation: 命令2 op3=>operation: 命令3 op4=>operation: 其它命令 cond=>condition: 模式名==模式1 ? cond2=>condition: 模式名==模式2 ? cond3=>condition: 模式名==模式3 ? e=>end st->io->cond cond(yes)->op->e cond(no)->cond2 cond2(yes)->op2->e cond2(no)->cond3 cond3(yes)->op3->e cond3(no)->op4->e
迴圈
for
for 變數名 in 取值列表 do 命令 done
for ((expr1;expr2;expr3)) do 命令 done
expr1 初值expr2 終值expr3 步長值
st=>start: Start op=>operation: 命令 op1=>operation: expr1 op3=>operation: expr3 cond=>condition: expr2為真 ? e=>end st->op1->cond cond(yes)->op->op3->cond cond(no)->e
IFS
#!/bin/bash data='a,b,c,d' IFS=, for i in $data;do echo $i done
while
while 條件表示式 do 命令 done
st=>start: Start op=>operation: 命令 cond=>condition: 條件表示式為真 ? e=>end st->cond cond(yes)->op->cond cond(no)->e
把a.txt檔案中的內容倒騰到b.txt檔案中
cat a.txt
1
2
3
4
5
6
7
8
9
10
cat b.txt
10
9
8
7
6
5
4
3
2
1 #!/bin/bash touch b.txt while [ -n "$(cat a.txt)" ] do if [ -z "$(cat b.txt)" ];then head -1 a.txt > b.txt else sed -i "1i `head -1 a.txt`" b.txt fi sed -i 1d a.txt done
while read
while read -p "請輸入:" do if [[ $REPLY =~ ^[0-9]+$ ]];then echo "輸出:$((REPLY*=${REPLY}00))" elif [[ "$REPLY" = "q" ]];then break fi done
while讀取檔案三種方式
1、 cat ./a.txt | while read LINE do echo $LINE done 2、 while read LINE do echo $LINE done < ./a.txt 3、 exec < ./a.txt while read LINE do echo $LINE done
break
break n 表示跳出迴圈的層數
省略n 表示跳出整個迴圈
continue
continue n退到第n層繼續迴圈
省略n表示跳出本次迴圈,繼續下一次迴圈
select
#PS3=[$USER@$0]# select VAR in var1 var2 quit do case $VAR in var1) echo 1 ;; var2) echo 2 ;; quit) break ;; esac done
函式
函式定義
function 函式名(){ 命令 }
函式引數
$1
$2
$3
$#
$*
$@
函式呼叫
函式名引數1引數2引數3
函式返回
- 返回數字作為函式執行狀態返回給$?取值範圍 0-255 (使用 return)
- 返回數字作為函式執行結果 (使用 echo)
- 返回字串,作為函式執行結果 (使用 echo)
系統函式庫
系統函式庫
/etc/init.d/functions
action函式
action "xxxxx" /bin/trueaction "xxxxx" /bin/false
功能函式庫
# 指令碼初始化 function scripts_init(){ prog=`basename $0 .sh` LockFile=/var/lock/subsys/${prog}.lock# 使用鎖檔案 LogFile=/var/log/${prog}.log# 指令碼記錄日誌 PidFile=/var/run/${prog}.pid# 記錄程序號,可以管理指令碼 [ -f $LockFile ] && echo "There $LockFile is exist!!" && exit 1 ||touch $LockFile [ ! -f $LogFile ] && touch $LogFile [ -f $PidFile ] && echo "There $PidFile is exist!!" && exit 2|| echo $$ > $PidFile } # 記錄日誌 function writelog(){ Date=$(date "+%F_%T") ShellName=`basename $0` Info=$1 echo "$Date : ${ShellName} : ${Info}" >> ${LogFile} } # 指令碼退出掃尾 function closeout(){ [ -f $LockFile ] && rm -f $LockFile [ -f $PidFile ]&& rm -f $PidFile } # 判斷輸入是整數 function int_judge(){ fun_a=$1 expr $fun_a + 1 &>/dev/null RETVAL=$? return $RETVAL } # 判斷輸入非空 function input_judge(){ RETVAL=0 fun_a=$1 [ ${#fun_a} -eq 0 ]&& RETVAL=1 return $RETVAL }
陣列
- 陣列名代表首地址
下標是從0開始的整數
普通陣列(索引陣列)
定義陣列
array=(a b c)
獲取所有元素
${array[*]}
獲取元素下標
${!a[@]}
獲取陣列長度
${#array[*]}
獲取一個元素的長度
${#name[0]}
獲取第一個元素
${array[0]}
獲取第二個元素
${array[1]}
獲取多個元素
array=(1 2 3 4 5) echo ${array[@]:1} 2 3 4 5 #array[@]:下標:擷取元素個數 echo ${array[@]:1:3} 2 3 4
新增元素
array[3]=d
新增多個元素
array+=(e f g)
刪除第一個元素
unset array[0]# 刪除會保留元素下標
刪除陣列
unset array
陣列切片
${name[4]:0:7}
關聯陣列
關聯陣列的下標是字串
定義關聯陣列
declare -A M
關聯陣列賦值
M=([a]=11 [b]=22)
獲取關聯陣列元素
echo ${M[a]} 11
獲取關聯陣列元素個數
echo ${#M[@]} 2
獲取關聯陣列下標
echo ${!M[*]} a b
獲取關聯陣列所有元素
echo ${M[@]} 11 22
新增元素
M[c]=33
新增多個元素
M+=([d]=33 [e]=44)
綜合題
找出一個網路中最大的空閒ip地址段
#!/bin/bash SUB_NET="10.0.0." for NUM in {1..254} do { if ping -c 1 ${SUB_NET}${NUM} &> /dev/null;then echo $NUM >> ip.txt fi }& done wait sort -n ip.txt -o ip.txt if [ $(tail -1 ip.txt) -ne 254 ];then echo 254 >> ip.txt fi while read LINE do array+=($LINE) done < ip.txt for ((i=0;i<${#array[*]}-1;i++)) do DIFF=$((${array[$((i+1))]}-${array[$i]})) echo -e "${SUB_NET}${array[$((i+1))]}\t${SUB_NET}${array[$i]}\t$DIFF" >> result.txt done sort -rnk3 result.txt rm *.txt -f
#!/bin/bash SUB_NET="10.0.0." for NUM in {1..254} do { if ping -c 1${SUB_NET}${NUM} &> /dev/null;then echo $NUM >> ip.txt fi }& done wait sort -n ip.txt -o ip.txt if [ $(tail -1 ip.txt) -ne 254 ];then echo 254 >> ip.txt fi awk -v net=$SUB_NET '{if(NR==1){last=$1}if(NR>1){printf "%s%d\t%s%d\t%d\n",net,$1,net,last,$1-last;last=$1}}' ip.txt |sort -nrk 3 rm ip.txt -f
抓鬮
#!/bin/bash function rand(){ echo $((RANDOM%100+1)) } > /tmp/user.txt while true do clear echo "抓鬮獲獎名單如下: " sort -rnk2 /tmp/user.txt |head -3 read -p 'please input name: ' NAME [ -z "$NAME" ] && continue if [ "$NAME" = "q" ];then break fi if grep -w "$NAME" /tmp/user.txt &> /dev/null;then continue fi RAND=$(rand) while grep -w "$RAND" /tmp/user.txt &> /dev/null do RAND=$(rand) done echo -e "$NAME\t$RAND" >>/tmp/user.txt done echo "抓鬮獲獎名單如下: " sort -rnk2 /tmp/user.txt |head -3