shell_script1,shellscript
1、簡介2、read3、運算工具4、if/then結構5、while迴圈6、for迴圈 一、簡介1、什麼是shellshell是使用者與系統互動作用的介面。shell是一種命令解釋程式,同時也是一種進階程式設計語言2、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)其中:Bash在日常工作中被廣泛使用;同時,Bash也是大多數Linux系統預設的Shell;3、shell局限性1.1、需要耗費大量資源的任務,特別是對執行速度要求較高的場合1.2、涉及大量的數學計算1.3.、關鍵性應用(資料庫,網站等)1.4.、設計圖形或者GUI的應用1.5.、需要直接存取硬體1.6.、開發閉源的應用(相對於開源)4、基礎檔案系統:Linux 的檔案系統是一個包含了目錄和檔案的分層的組織圖,位於最頂端的叫做根目錄(root directory),用斜杠/ 來表示目錄: 是一種包含目錄項的檔案,每個目錄項中都包含了檔案名稱檔案名稱: 目錄的內容稱為目錄項,目錄項包含了檔案名稱,只有兩種字元不允許出現在檔案名稱中:斜杠,Null 字元(ASCII 值為0),斜杠用於分隔路徑中的檔案名稱,Null 字元用來表示路徑的結尾。檔案名稱的長度通常可以達到255個字元路徑: 一系列檔案名稱連起來,用斜杠分隔,就叫做路徑,路徑用於表示檔案的位置;以斜杠開頭的路徑叫做絕對路徑,否則為相對路徑,相對路徑相對於當前工作目錄返回碼:所有命令都有一個傳回值,用0-255之間的整數來表示;指令碼就是一個命令,它也有傳回值,另外,指令碼裡面的函數也有傳回值退出指令碼的正規方法是明確地用命令exit [code]來退出,如:exit 0;exit $? 二、read1、定義read是一個buildin命令,主要完成對參數的賦值,類似C語言中的scanf;其不僅可以賦值變數,還可以賦值數組;其輸入不僅是螢幕,還可以是檔案描述符2、實操# read a --輸入字串,將字串賦值給變數 a;# echo $ahello world!!# read name sex age --同時分別給三個變數賦值,輸入分隔字元預設為 空格符zhangsan male 50# unset name sex age --刪除變數# IFS=';' --將 read 的輸入分隔字元改為 ';'# vim test.sh#!/bin/bashprompt="Please enter your name:"read -p "$prompt" nameecho "Greetings $name" 三、運算工具1、簡單數學運算# echo $((1+2**2-3*4/5%6)) --輸出計算結果到螢幕# a=$((1+2**2-3*4/5%6)) --把計算結果賦給變數a# ((a=1+2**2-3*4/5%6)) --同上# echo "scale=3;10/3" | bc --bc計算機;保留小數點後三位# echo "2^10" | bc --bc計算機;計算2的10次方# awk 'BEGIN{print 1/3}' --awk計算2、擷取隨機數# od -N4 -tu4 /dev/urandom | sed -n '1s/.* //p' --擷取一個7位元的號碼# od -Ad -w24 -tu4 /dev/urandom --擷取隨機數# od -tu8 /dev/urandom --擷取隨機數# od -tu8 /dev/urandom | sed -r 's/^[0-9]+\s+//' | sed -r 's/\s+/\n/g' |cut -b1-8 |sed -r -n '/^.{8}$/p' | sed 's/^/186/' |head -n5000 |vi - --擷取一萬個電話號碼# od -N40000 -tu4 /dev/urandom | sed -r 's/^[0-9]+(\s+)?//' | sed -r 's/\s+/\n/g' | grep -vE '^\s*$' > 10k_random --產生一萬個隨機數# sed -r -n '/^.{8}$/p' 10k_random | head -n 100000 | sed 's/^/186/' > phone_num3、擷取數字序列# seq 10 --擷取1到10# seq 1 2 10 --擷取1到10,步長為2# seq 10 100 --擷取10到100# seq 10 -1 1 --倒序,10到1 四、if/then執行個體1、判斷字元 "a" 是否等於 "A"# vim test.sh#!/bin/bashif [[ "a" = "A" ]]; thenif [ "a" = "A" ]; then echo "a equals A"else echo "a no equals A"fi2、判斷/root/test/test.sh是否存在並具有可執行許可權# vim test.sh#!/bin/bashif test -x /root/test/test.sh;then echo "/root/test/test.sh is executable"fi3、判斷系統是否存在 root 使用者# vim test.sh#!/bin/bashif grep -E --color=auto ^root: /etc/passwd; then echo "user root exists"fi4、判斷檔案類型# vim test.sh#!/bin/bashfunction isSymbolicLink() { file=$1 flag=$(ls -ld $file | cut -b1) test "$flag" = "1" return $?}file=$1if isSymbolicLink $file; then echo "Symbolic Link"elif test -d $file; then echo "Directory file"elif test -f $file; then echo "Regular file"elif test -b $file; then echo "Block special"elif test -c $file; then echo "Character special"elif test -p $file; then echo "Named pipe"elif test -S $file; then echo "Socket"else echo "Unkown"fi5、判斷輸入數位大小# vim test.sh#!/bin/bashnum=$1if test "$num" -lt 10 ;then echo "小數字"elif test "$num" -lt 20;then echo "中數字"elif test "$num" -lt 30;then echo "大數字"else echo "超大數字"fi6、從標準輸入擷取一個數字,並根據其大小輸出指定字串# vim test.sh#!/bin/bashecho -n "Enter a number: "read numif [ "$num" -lt 100 ]; thenecho "小於100"elif [ "$num" -ge 100 -a "$num" -lt 200 ]; thenecho "大於等於100小於200"elif [ "$num" -ge 200 -a "$num" -lt 300 ]; thenecho "大於等於200小於300"elseecho "其它數字"fi 五、wihle迴圈1、認識測試 while 關鍵字後面一條命令的返回碼,條件為真時,程式讀入while迴圈體中的指令;0為真。迴圈體如下:while [] --while 後面運行 [ ] 命令,測試 [ ] 命令的返回碼cat /filename | while read line --while 後面運行read 命令,測試 read 命令的返回碼do......done2、迴圈控制語句continue --終止當前迴圈,開始下一個迴圈break --終止當前迴圈,並退出迴圈體exit --終止當前指令碼3、執行個體# vim test.sh --區分 continue 與 break 的區別#!/bin/bashwhile truedosleep 1echo testcontinue/breakechodone# vim test.sh --區分 break 與 exit 的區別#!/bin/bashwhile test -e /data/test/test.shdoecho "exists"sleep 1break/exitdoneecho "loop end"# vim test.sh --尋找我們給定的路徑,直到尋到為止 #!/bin/bashif test $# -ne 1;thenecho "wrong paraneter" >&2exitfipath=$1while test ! -e "$path"dosleep 1echo "don't found!!!"doneecho "found"# vim test.sh --指令碼運行指定的時間,時間一到就退出;單位為 s#!/bin/bashif test $# -ne 1;thenecho "Usage: $(basename $0) TIME" >&2exit 1fitimeLength=$1beginTime=$(date +%s)endTime=$(( $beginTime + $timeLength ))---------------------------------------------------------while test $(date +%s) -lt "$endTime"doecho "processing....."sleep 1done---------------------------------------------------------while truedoif test $(date +%s) -ge "$endTime";thenbreakfiecho "processing....."sleep 1done---------------------------------------------------------echo "time out"# vim test.sh --迴圈讀取檔案的每一行,並計算每行的字元個數#!/bin/bashfile=$1---------------------------------------------------------totalLines=$(wc -l < $file)line=1while test $line -le $totalLinesdolineData=$(sed -n "${line}p" $file)len=$(echo -n $lineData | wc -c)echo "line ${line}: $len"line=$(( $line + 1 ))done---------------------------------------------------------line=1while read lineDatadolen=$(echo $lineData | wc -c)echo "line ${line}: $len"line=$(( $line + 1 ))done < $file---------------------------------------------------------# vim test.sh -- 列印出10行hello world;<(seq 10)相當於一個檔案路徑;稱之為進程置換#!/bin/bashwhile read numdoecho "hello world"done < <(seq 10)---------------------------------------------------------n=1while [ $n -le 10 ]doecho "hello world"n=$((n+1))done---------------------------------------------------------# vim test.sh --建立一個不盡的迴圈,要求迴圈運行1分鐘後自動終止#!/bin/bashstart_time=$(date +%s)while truedocur_time=$(date +%s)test $((cur_time - start_time)) -ge 10 && breaktime=$((cur_time - start_time))echo "time is $time......"sleep 1done# vim test.sh --先用while 迴圈建立100個.txt檔案;再將所有檔案尾碼名改為 .html#!/bin/bashcount=100---------------------------------------------------------seq $count | while read idotouch ${i}.txtdonels -1 *.txt | while read oldnamedonewname=$(echo $oldname | sed 's/.txt$/.html/')mv $oldname $newnamedone---------------------------------------------------------while read idotouch ${i}.txtdone < <( seq $count )while read oldnamedonewname=$(echo $oldname | sed 's/.txt$/.html/')mv $oldname $newnamedone < <(ls -1 *.txt )# vim test.sh --計算出1000 之內的偶數的和;不能使用管道,因為管道會產生子進程#!/bin/bashsum=0while read numdosum=$(( $sum + $num ))done < <(seq 2 2 998)echo "sum: $sum "# vim test.sh --大量新增100個郵件使用者,使用者名稱為u1 至u100,密碼為abc,登入shell 為/sbin/nologin,只屬於email組#!/bin/bashpassword=abcgroup=emailgrep -Eq "^${group}:" /etc/group || groupadd $groupwhile read idouseradd u${i} -N -g $group -s /sbin/nologinpasswd u${i} --stdin <<< "$password"done < <(seq 100)# vim test.sh --大量刪除剛剛建立的100個郵件使用者#!/bin/bashwhile read idouserdel -r u${i}done < <(seq 100 六、for 迴圈在一系列由分隔字元隔開的字串中,按順序每次取其中之一,當取完之後,迴圈結束每次取出的字串會被儲存在一個變數中,可以在迴圈體內使用該變數由分隔字元隔開的字串可以通過以下方法提供:1、手動輸入字串,用於迴圈指定次數# vim test.sh#!/bin/bashfor i in 1 2 3doecho $idon2、由變數提供字串# vim test.sh#!/bin/bashFILES="/bin/bash /bin/ls /bin/cat"for file in $FILES doecho $filedone3、程式產生的字串# vim test.sh#!/bin/bashfor n in $(seq 11)do echo $ndone4、由shell 展開而產生,迴圈目錄中的檔案# vim test.sh#!/bin/bashfor f in /etc/init.d/*doecho $fdone# vim test.sh5、列印出/dev 下面所有以 loop 開頭的檔案的檔案名稱# vim test.sh#!/bin/bashfor file in /dev/loop*doecho $(basename $file)done6、計算出1000 之內的偶數的和# vim test.sh#!/bin/bashsum=0for number in $(seq 2 2 998)do sum=$(( $sum + $number ))doneecho "total: $sum"7、大量新增100個郵件使用者,使用者名稱為u1 至u10,密碼為abc,登入shell 為/sbin/nologin,只屬於email組# vim test.sh#!/bin/bashfunction checkGid() {gid=$1if ! grep -qE "^$gid:" /etc/group; thengroupadd $gidfi}function isRoot() {id=$(id | awk -F "[=(]" '{print $2}')if test "$id" -ne 0; thenecho "must be root" >&2exit 1fi}count=10namePrefix=upassword=abcshell=/sbin/nologingid=emailisRootcheckGid $gidfor num in $(seq $count)doname=${namePrefix}${num}useradd $name -s $shell -g $gid &> /dev/nullif test $? -ne 0; thenecho "failed to create $name" >&2elseecho "created successfully -- $name"echo "$password" | passwd --stdin $name &> /dev/nullif test $? -ne 0; thenecho "failed to change password for $name" >&2elseecho "password changed successfully -- $name"fifidone8、擷取區域網路內所有電腦的IP 和MAC 位址的對應表# vim test.sh#!/bin/bashipPrefix=192.168.1.startIp=1endIp=254for num in $(seq $startIp $endIp)doip=${ipPrefix}$numping -W1 -c1 $ip &>/dev/null &donewaitarp -n | sed '/incomplete/d' | awk '{print $1,$3}'| cat | sort -n -t '.' -k4,4 | column -t9、列印出九九乘法表# vim test.sh#!/bin/bashfor row in $(seq 9)dofor col in $(seq $row)doecho -n "${col}x${row}=$(( $col * $row )) "doneechodone | column -t10、簡陋計算機#!/bin/bashvarnum=3if test "$#" -ne "$varnum"; thenecho "wrong argument" >&2exit 1finum1=$1num2=$3operator=$2if test "$operator" = "x";thenoperator="*"fiif test "$operator" = "/" -a "$num2" = 0; thenecho "division by 0" >& 2exit 1firesult=$(( $num1 $operator $num2 ))echo "$result"注意:乘法的處理;被除數為0時的處理11、把指定目錄下的某些檔案複製到指定的目錄,要求:#1. 從命令列參數接收兩個參數,分別是來源目錄和目標目錄#2. 如果來源目錄不存在,應該報錯#3. 如果目標目錄不存在,就建立一個#4. 如果目標已經存在但不是目錄,就報錯#5. 只複製常規檔案,軟連結檔案#6. 對於常規檔案,只複製大小小於1M 的檔案# vim /test.sh#!/bin/bashfunction displayHelp(){echo "Usage: $(basename $0) SRCDIR DSTDIR"}function getSize(){file=$1size=$(ls -l $file | awk '{print $5}')echo $size}if test $# -ne 2; thendisplayHelp >&2exit 1fisrcdir=$1dstdir=$2if test ! -d "$srcdir"; thenecho "$srcdir not exists or is not a directory" >&2exit 1fiif test ! -e "$dstdir"; thenmkdir "$dstdir"fiif test ! -d "$dstdir"; thenecho "$dstdir is not a directory" >&2exit 1fifor file in $srcdir/*doif test -L $file; thencp -a $file $dstdir/elif test -f $file; then---------------------------------------------------size=$(getSize $file)if test "$size" -lt 1048576; thencp -a $file $dstdir/fi---------------------------------------------------find $file -type f -size -1024k -exec cp -a {} $dstdir/ \;---------------------------------------------------fidone