shell腳本編程之一
shell腳本基礎
shell腳本是包含一些命令或聲明,并符合一定格式的文本文件
格式要求:首行shebang機制
#!/bin/bash #!/usr/bin/python #!/usr/bin/perl
shell腳本的用途有:
-
自動化常用命令
-
執行系統管理和故障排除
-
常見簡單的應用程序
-
處理文本或文件
創建shell腳本
第一步:使用文本編輯器來創建文本文件
-
第一行必須包括shell聲明序列:#!
#!/bin/bash
添加注釋
注釋以#開頭
-
第二步:運行腳本
給予執行權限,在命令行指定腳本的絕對或相對路徑
直接運行解釋器,將腳本作為解釋器程序的參數運行
shell腳本范例
#!/bin/bash #author:root #Version:1.0 #description:the script displays some information about your environment echo "greentings.the date and tiem are $(date)" echo "your working directory is :$(pwd)"
腳本調試
bash -n /path/to/some_script 檢測腳本中的語法錯誤 bash -x /path/to/some_script 調試執行
變量
-
變量:命名的內存空間
數據存儲方式
字符:
數值:整形,浮點型
-
變量:變量類型
作用:
1、數據存儲格式
2、參與的運算
3、表示的數據范圍
類型
字符
數值:整形、浮點型
編程語言的分類
強類型:Java、Python
弱類型:bash
變量命名法則:
1、不能使程序中的保留字:例如if, for;
2、只能使用數字、字母及下劃線,且不能以數字開頭
3、見名知義
4、統一命名規則:駝峰命名法
bash中變量的種類
根據變量的生效范圍等標準
本地變量:生效范圍為當前shell;對當前shell之外的其他shell進程,包括但當前shell的字shell進程均無效
環境變量:生效范圍為當前shell進程及其子進程
局部變量:生效范圍為當前shell進程中某代碼片段(通常指函數)
位置變量:$1,$2…${10}..來表示,用于讓腳步在腳本代碼中調用通過命令行傳遞給它的參數
特殊變量:$? $0 $* $@ $#
本地變量 變量賦值:name=‘value’, 可以使用引用value: (1) 可以是直接字串; name=“root" (2) 變量引用:name="$USER" (3) 命令引用:name=`COMMAND`, name=$(COMMAND) 變量引用:${name}, $name "":弱引用,其中的變量引用會被替換為變量值 '':強引用,其中的變量引用不會被替換為變量值,而保持原字符串 顯示已定義的所有變量:set 刪除變量:unset name 環境變量 變量聲明、賦值: export name=VALUE declare -x name=VALUE 變量引用:$name, ${name} 顯示所有環境變量: export env printenv 刪除:unset name bash有許多內建的環境變量:PATH, SHELL, USRE,UID, HISTSIZE, HOME, PWD, OLDPWD, HISTFILE, PS1 只讀和位置變量 只讀變量:只能聲時,但不能修改和刪除 readonlyname declare -r name 位置變量:在腳本代碼中調用通過命令行傳遞給腳本的參數 $1, $2, ...:對應第1、第2等參數,shift [n]換位置 $0: 命令本身 $*: 傳遞給腳本的所有參數,全部參數合為一個字符串 $@: 傳遞給腳本的所有參數,每個參數為獨立字符串 $#: 傳遞給腳本的參數的個數 $@ $* 只在被雙引號包起來的時候才會有差異 示例:判斷給出的文件的行數 linecount="$(wc-l $1| cut -d' ' -f1)" echo "$1 has $linecountlines." 算術運算 bash中的算術運算:help let +, -, *, /, %取模(取余), **(乘方) 實現算術運算: (1) let var=算術表達式 (2) var=$[算術表達式] (3) var=$((算術表達式)) (4) var=$(expr arg1 arg2 arg3 ...) (5) declare –ivar= 數值 (6) echo ‘算術表達式’ | bc 乘法符號有些場景中需要轉要轉義,如* bash有內建的隨機數生成器:$RANDOM(1-32767) echo $[$RANDOM%50] :0-49之間隨機數
邏輯運算
true 0
false 1
短路運算:
短路與:
第一個為0,結果必定為0
第一個為1,第二個必須要參與運算;
短路或:
第一個為1,結果必定為1;
第一個為0,第二個必須要參與運算;
聚集命令
兩種聚集命令的方法:
復合式:date ; who | wc -l
命令會一個接一個地運行
子shell:(date ; who | wc -l) >> /tmp?trace
所有輸出都被發送給單個stdout和stderr
退出狀態
0 表示成功,1-255代表失敗
$? 變量保存最近的命令退出狀態
example
$ ping -c1 -w1 hostdown $> /dev/null
$ echo $?
退出狀態嗎
bash自定義退出狀態碼
extinct [n]:自定義退出狀態碼
注意:腳本中一旦遇到exit命令,腳本會立即終止;終止退出狀態取決于exit命令后面的數字
注意:若果為給腳本指定退出狀態碼,整個腳本的退出狀態碼取決于腳本中執行的最后一條命令的狀態碼
條件測試 判斷某需求是否滿足,需要由測試機制來實現; 專用的測試表達式需要由測試命令輔助完成測試過程; 評估布爾聲明,以便用在條件性執行中 ?若真,則返回0 ?若假,則返回1 測試命令: ?test EXPRESSION ?[ EXPRESSION ] ?[[ EXPRESSION ]] 注意:EXPRESSION前后必須有空白字符 根據退出狀態而定,命令可以有條件地運行 ?&& 代表條件性的AND THEN ?|| 代表條件性的OR ELSE test命令 長格式的例子: $test "$A" == "$B" && echo"Stringsareequal" $test “$A” -eq “$B” && echo "Integersareequal" 簡寫格式的例子: $[ "$A" == "$B" ] && echo"Stringsareequal" $[ "$A" -eq "$B" ] && echo "Integersareequal"
bash的測試類型
數值測試
-gt: 是否大于; -ge: 是否大于等于; -eq: 是否等于; -ne: 是否不等于; -lt: 是否小于; -le: 是否小于等于;
字符串測試
==:是否等于; >: ascii碼是否大于ascii碼 <: 是否小于 !=: 是否不等于 =~: 左側字符串是否能夠被右側的PATTERN所匹配 注意: 此表達式一般用于[[ ]]中; -z "STRING":字符串是否為空,空為真,不空為假 -n "STRING":字符串是否不空,不空為真,空為假 注意:用于字符串比較時的用到的操作數都應該使用引號 文件測試 存在性測試 -a FILE:同-e -e FILE: 文件存在性測試,存在為真,否則為假; 存在性及類別測試 -b FILE:是否存在且為塊設備文件; -c FILE:是否存在且為字符設備文件; -d FILE:是否存在且為目錄文件; -f FILE:是否存在且為普通文件; -h FILE 或-L FILE:存在且為符號鏈接文件; -p FILE:是否存在且為命名管道文件; -S FILE:是否存在且為套接字文件; 文件權限測試: -r FILE:是否存在且可讀 -w FILE: 是否存在且可寫 -x FILE: 是否存在且可執行 文件特殊權限測試: -g FILE:是否存在且擁有sgid權限; -u FILE:是否存在且擁有suid權限; -k FILE:是否存在且擁有sticky權限; 文件大小測試: -s FILE: 是否存在且非空; 文件是否打開: -t fd: fd表示文件描述符是否已經打開且與某終端相關 -N FILE:文件自上一次被讀取之后是否被修改過 -O FILE:當前有效用戶是否為文件屬主 -G FILE:當前有效用戶是否為文件屬組 雙目測試: FILE1 -efFILE2: FILE1與FILE2是否指向同一個設備上的相同inode FILE1 -ntFILE2: FILE1是否新于FILE2; FILE1 -otFILE2: FILE1是否舊于FILE2; 組合條件測試 第一種方式: COMMAND1 && COMMAND2 并且 COMMAND1 || COMMAND2 或者 ! COMMAND 非 如:[ -e FILE ] && [ -r 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 附加:bash特殊變量$* $@詳解 [root@centos7 sh]# cat arg1.sh ./arg2.sh "$*" echo =================== ./arg2.sh "$@" [root@centos7 sh]# cat arg2.sh echo 1st is "$1" echo 2st is "$2" echo all args are is "$*" echo number is "$#" [root@centos7 sh]# arg1.sh openstack mysql marindb 1st is openstack mysql marindb 2st is all args are is openstack mysql marindb number is 1 =================== 1st is openstack 2st is mysql all args are is openstack mysql marindb number is 3 重以上的實例中我們可以看到 $* 把所有的參數當做一個參數來輸入 $@ 原來有幾個參數,輸出還是幾個 注:對于位置參數為$1 $2 $3... 當多個10的時候 我們采用 ${11} ${12} ... 這種方法表示即可
下面用幾道練習題來加深印象
1、編寫腳本/root/bin/systeminfo.sh,顯示當前主機系統信息,包括主機名,IPv4地址,操作系統版本,內核版本,CPU型號,內存大小,硬盤大小。
2、編寫腳本/root/bin/backup.sh,可實現每日將/etc/目錄備份到/root/etcYYYY-mm-dd中
3、編寫腳本/root/bin/disk.sh,顯示當前硬盤分區中空間利用率最大的值
4、編寫腳本/root/bin/links.sh,顯示正連接本主機的每個遠程主機的IPv4地址和連接數,并按連接數從大到小排序
5、寫一個腳本/root/bin/sumid.sh,計算/etc/passwd文件中的第10個用戶和第20用戶的ID之和
6、寫一個腳本/root/bin/sumspace.sh,傳遞兩個文件路徑作為參數給腳本,計算這兩個文件中所有空白行之和
7、寫一個腳本/root/bin/sumfile.sh,統計/etc, /var, /usr目錄中共有多少個一級子目錄和文件
8、寫一個腳本/root/bin/argsnum.sh,接受一個文件路徑作為參數;如果參數個數小于1,則提示用戶“至少應該給一個參數”,并立即退出;如果參數個數不小于1,則顯示第一個參數所指向的文件中的空白行數
9、寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址做為參數,測試是否可連通。如果能ping通,則提示用戶“該IP地址可訪問”;如果不可ping通,則提示用戶“該IP地址不可訪問”
10、chmod -rw /tmp/file1,編寫腳本/root/bin/per.sh,判斷當前用戶對/tmp/fiile1文件是否不可讀且不可寫
附錄參考:
第一題
#!/bin/bash host_name=`hostname` Ipv4_addr=`ifconfig | grep -A 1 '^e' | tail -1 | sed -r 's@inet (addr:)?(.*) (netmask|Bc).*@\2@' | tr -d ' '` os_version=`cat /etc/redhat-release` kernel_version=`uname -r` CPU_type=`cat /proc/cpuinfo | grep "model name" | cut -d: -f2 | tr -d ' '` mem_size=`cat /proc/meminfo | grep "MemT"| cut -d: -f2 | tr -d ' '` disk_size=`fdisk -l /dev/sda | sed -rn "s@Disk /dev/sd[a-z]: (.*), .*, .*@\1@p"` red="\033[31m" end_color="\033[0m" echo -e "${red}Current OS information$end_color" echo "hostname is $host_name" echo "ipaddr is $Ipv4_addr" echo "OS version is $os_version" echo "kernel version is $kernel_version" echo "cpu type is $CPU_type" echo "mem size is $mem_size" echo "disk size is $disk_size"
第二題
#!/bin/bash backup_file="/etc/" cp -ar $backup_file /root/etc`date +%F`
第三題
#!/bin/bash total=`df | sed -rn 's@/(dev/sd[a-z][0-9]+).* ([0-9]+)%.*@\1:\2@p' | sort -nr -t: -k2 | head -1` max_diskuse_name=`echo $total | cut -d: -f1` max_diskuse_number=`echo $total | cut -d: -f2` echo "Max disk use name is $max_diskuse_name" echo "IT use ${max_diskuse_number}%" ~
第四題
#!/bin/bash links=`netstat -tn | grep "^tcp" | tr -s ' ' | cut -d' ' -f4 | cut -d: -f1 | sort | uniq -c | sort -r` links_number=`echo $links | wc -l` echo "links number is $links_number" echo -e "they are\n$links"
第五題
#!/bin/bash uid_10=`cat /etc/passwd | sed -n '10p' | cut -d: -f3` uid_20=`cat /etc/passwd | sed -n '20p' | cut -d: -f3` total=$[$uid_10+$uid_20] echo "The 10st UID is $uid_10" echo "The 20st UID is $uid_20" echo "The sum of is $total"
第六題
#!/bin/bash first_spacelines=`cat $1 | grep "^$" | wc -l` second_spacelines=`cat $2 | grep "^$" | wc -l` total=$[$first_spacelines+$second_spacelines] echo "the 1st spacelines is $first_spacelines" echo "the 2st spacelines is $second_spacelines" echo "the sum of id $total" ~
第七題
#!/bin/bash total=`ls -A /etc/ /var/ /usr | wc -l` echo "the sum of is $total" ~
第八題
#!/bin/bash [ $# -lt 1 ] && echo "at least one arg" && exit || cat $1 | grep "^$" | wc -l
第九題
#!/bin/bash ping -c1 -W1 $1 &> /dev/null && echo "$1 is up" || echo "$1 is down"
第十題
#!/bin/bash [ ! -r /tmp/file1 -a ! -w /tmp/file1 ] && echo "not write and not read" || echo "match fail"
原創文章,作者:sixijie,如若轉載,請注明出處:http://www.www58058.com/36202