1、簡介 2、read 3、運算工具 4、if/then結構 5、while迴圈 6、for迴圈 一、簡介 1、什麼是shell shell是用戶與系統交互作用的界面。shell是一種命令解釋程式,同時也是一種高級程式設計語言 2、shell常見種類 Bourne Shell(/usr/bin/sh ...
1、簡介 2、read 3、運算工具 4、if/then結構 5、while迴圈 6、for迴圈 一、簡介 1、什麼是shell shell是用戶與系統交互作用的界面。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),用斜杠/ 來表示 目錄: 是一種包含目錄項的文件,每個目錄項中都包含了文件名 文件名: 目錄的內容稱為目錄項,目錄項包含了文件名,只有兩種字元不允許出現在文件名中:斜杠,空字元(ASCII 值為0),斜杠用於分隔路徑中的文件名,空字元用來表示路徑的結尾。文件名的長度通常可以達到255個字元 路徑: 一系列文件名連起來,用斜杠分隔,就叫做路徑,路徑用於表示文件的位置;以斜杠開頭的路徑叫做絕對路徑,否則為相對路徑,相對路徑相對於當前工作目錄 返回碼:所有命令都有一個返回值,用0-255之間的整數來表示;腳本就是一個命令,它也有返回值,另外,腳本裡面的函數也有返回值 退出腳本的正規方法是明確地用命令exit [code]來退出,如:exit 0;exit $? 二、read 1、定義 read是一個buildin命令,主要完成對參數的賦值,類似C語言中的scanf; 其不僅可以賦值變數,還可以賦值數組; 其輸入不僅是屏幕,還可以是文件描述符 2、實操 # read a --輸入字元串,將字元串賦值給變數 a;# echo $a hello world!! # read name sex age --同時分別給三個變數賦值,輸入分隔符預設為 空格符 zhangsan male 50 # unset name sex age --刪除變數 # IFS=';' --將 read 的輸入分隔符改為 ';' # vim test.sh #!/bin/bash prompt="Please enter your name:" read -p "$prompt" name echo "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_num 3、獲取數字序列 # 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/bash if [[ "a" = "A" ]]; then if [ "a" = "A" ]; then echo "a equals A" else echo "a no equals A" fi 2、判斷/root/test/test.sh是否存在並具有可執行許可權 # vim test.sh #!/bin/bash if test -x /root/test/test.sh;then echo "/root/test/test.sh is executable" fi 3、判斷系統是否存在 root 用戶 # vim test.sh #!/bin/bash if grep -E --color=auto ^root: /etc/passwd; then echo "user root exists" fi 4、判斷文件類型 # vim test.sh #!/bin/bash function isSymbolicLink() { file=$1 flag=$(ls -ld $file | cut -b1) test "$flag" = "1" return $? } file=$1 if 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" fi 5、判斷輸入數字的大小 # vim test.sh #!/bin/bash num=$1 if test "$num" -lt 10 ;then echo "小數字" elif test "$num" -lt 20;then echo "中數字" elif test "$num" -lt 30;then echo "大數字" else echo "超大數字" fi 6、從標準輸入獲取一個數字,並根據其大小輸出指定字元串 # vim test.sh #!/bin/bash echo -n "Enter a number: " read num if [ "$num" -lt 100 ]; then echo "小於100" elif [ "$num" -ge 100 -a "$num" -lt 200 ]; then echo "大於等於100小於200" elif [ "$num" -ge 200 -a "$num" -lt 300 ]; then echo "大於等於200小於300" else echo "其它數字" fi 五、wihle迴圈 1、認識 測試 while 關鍵字後面一條命令的返回碼,條件為真時,程式讀入while迴圈體中的指令;0為真。迴圈體如下: while [] --while 後面運行 [ ] 命令,測試 [ ] 命令的返回碼 cat /filename | while read line --while 後面運行read 命令,測試 read 命令的返回碼 do ...... done 2、迴圈控制語句 continue --終止當前迴圈,開始下一個迴圈 break --終止當前迴圈,並退出迴圈體 exit --終止當前腳本 3、實例 # vim test.sh --區分 continue 與 break 的區別 #!/bin/bash while true do sleep 1 echo test continue/break echo done # vim test.sh --區分 break 與 exit 的區別 #!/bin/bash while test -e /data/test/test.sh do echo "exists" sleep 1 break/exit done echo "loop end" # vim test.sh --尋找我們給定的路徑,直到尋到為止 #!/bin/bash if test $# -ne 1;then echo "wrong paraneter" >&2 exit fi path=$1 while test ! -e "$path" do sleep 1 echo "don't found!!!" done echo "found" # vim test.sh --腳本運行指定的時間,時間一到就退出;單位為 s #!/bin/bash if test $# -ne 1;then echo "Usage: $(basename $0) TIME" >&2 exit 1 fi timeLength=$1 beginTime=$(date +%s) endTime=$(( $beginTime + $timeLength )) --------------------------------------------------------- while test $(date +%s) -lt "$endTime" do echo "processing....." sleep 1 done --------------------------------------------------------- while true do if test $(date +%s) -ge "$endTime";then break fi echo "processing....." sleep 1 done --------------------------------------------------------- echo "time out" # vim test.sh --迴圈讀取文件的每一行,並計算每行的字元個數 #!/bin/bash file=$1 --------------------------------------------------------- totalLines=$(wc -l < $file) line=1 while test $line -le $totalLines do lineData=$(sed -n "${line}p" $file) len=$(echo -n $lineData | wc -c) echo "line ${line}: $len" line=$(( $line + 1 )) done --------------------------------------------------------- line=1 while read lineData do len=$(echo $lineData | wc -c) echo "line ${line}: $len" line=$(( $line + 1 )) done < $file --------------------------------------------------------- # vim test.sh -- 列印出10行hello world;<(seq 10)相當於一個文件路徑;稱之為進程置換 #!/bin/bash while read num do echo "hello world" done < <(seq 10) --------------------------------------------------------- n=1 while [ $n -le 10 ] do echo "hello world" n=$((n+1)) done --------------------------------------------------------- # vim test.sh --創建一個不盡的迴圈,要求迴圈運行1分鐘後自動終止 #!/bin/bash start_time=$(date +%s) while true do cur_time=$(date +%s) test $((cur_time - start_time)) -ge 10 && break time=$((cur_time - start_time)) echo "time is $time......" sleep 1 done # vim test.sh --先用while 迴圈創建100個.txt文件;再將所有文件尾碼名改為 .html #!/bin/bash count=100 --------------------------------------------------------- seq $count | while read i do touch ${i}.txt done ls -1 *.txt | while read oldname do newname=$(echo $oldname | sed 's/.txt$/.html/') mv $oldname $newname done --------------------------------------------------------- while read i do touch ${i}.txt done < <( seq $count ) while read oldname do newname=$(echo $oldname | sed 's/.txt$/.html/') mv $oldname $newname done < <(ls -1 *.txt ) # vim test.sh --計算出1000 之內的偶數的和;不能使用管道,因為管道會生成子進程 #!/bin/bash sum=0 while read num do sum=$(( $sum + $num )) done < <(seq 2 2 998) echo "sum: $sum " # vim test.sh --批量添加100個郵件用戶,用戶名為u1 至u100,密碼為abc,登錄shell 為/sbin/nologin,只屬於email組 #!/bin/bash password=abc group=email grep -Eq "^${group}:" /etc/group || groupadd $group while read i do useradd u${i} -N -g $group -s /sbin/nologin passwd u${i} --stdin <<< "$password" done < <(seq 100) # vim test.sh --批量刪除剛剛創建的100個郵件用戶 #!/bin/bash while read i do userdel -r u${i} done < <(seq 100 六、for 迴圈 在一系列由分隔符隔開的字元串中,按順序每次取其中之一,當取完之後,迴圈結束 每次取出的字元串會被保存在一個變數中,可以在迴圈體內使用該變數 由分隔符隔開的字元串可以通過以下方法提供: 1、手動輸入字元串,用於迴圈指定次數 # vim test.sh #!/bin/bash for i in 1 2 3 do echo $i don 2、由變數提供字元串 # vim test.sh #!/bin/bash FILES="/bin/bash /bin/ls /bin/cat" for file in $FILES do echo $file done 3、程式生成的字元串 # vim test.sh #!/bin/bash for n in $(seq 11) do echo $n done 4、由shell 展開而生成,迴圈目錄中的文件 # vim test.sh #!/bin/bash for f in /etc/init.d/* do echo $f done # vim test.sh 5、列印出/dev 下麵所有以 loop 開頭的文件的文件名 # vim test.sh #!/bin/bash for file in /dev/loop* do echo $(basename $file) done 6、計算出1000 之內的偶數的和 # vim test.sh #!/bin/bash sum=0 for number in $(seq 2 2 998) do sum=$(( $sum + $number )) done echo "total: $sum" 7、批量添加100個郵件用戶,用戶名為u1 至u10,密碼為abc,登錄shell 為/sbin/nologin,只屬於email組 # vim test.sh #!/bin/bash function checkGid() { gid=$1 if ! grep -qE "^$gid:" /etc/group; then groupadd $gid fi } function isRoot() { id=$(id | awk -F "[=(]" '{print $2}') if test "$id" -ne 0; then echo "must be root" >&2 exit 1 fi } count=10 namePrefix=u password=abc shell=/sbin/nologin gid=email isRoot checkGid $gid for num in $(seq $count) do name=${namePrefix}${num} useradd $name -s $shell -g $gid &> /dev/null if test $? -ne 0; then echo "failed to create $name" >&2 else echo "created successfully -- $name" echo "$password" | passwd --stdin $name &> /dev/null if test $? -ne 0; then echo "failed to change password for $name" >&2 else echo "password changed successfully -- $name" fi fi done 8、獲取區域網內所有電腦的IP 和MAC 地址的對應表 # vim test.sh #!/bin/bash ipPrefix=192.168.1. startIp=1 endIp=254 for num in $(seq $startIp $endIp) do ip=${ipPrefix}$num ping -W1 -c1 $ip &>/dev/null & done wait arp -n | sed '/incomplete/d' | awk '{print $1,$3}'| cat | sort -n -t '.' -k4,4 | column -t 9、列印出九九乘法表 # vim test.sh #!/bin/bash for row in $(seq 9) do for col in $(seq $row) do echo -n "${col}x${row}=$(( $col * $row )) " done echo done | column -t 10、簡陋計算器 #!/bin/bash varnum=3 if test "$#" -ne "$varnum"; then echo "wrong argument" >&2 exit 1 fi num1=$1 num2=$3 operator=$2 if test "$operator" = "x";then operator="*" fi if test "$operator" = "/" -a "$num2" = 0; then echo "division by 0" >& 2 exit 1 fi result=$(( $num1 $operator $num2 )) echo "$result" 註意:乘法的處理;被除數為0時的處理 11、把指定目錄下的某些文件複製到指定的目錄,要求: #1. 從命令行參數接收兩個參數,分別是源目錄和目標目錄 #2. 如果源目錄不存在,應該報錯 #3. 如果目標目錄不存在,就創建一個 #4. 如果目標已經存在但不是目錄,就報錯 #5. 只複製常規文件,軟鏈接文件 #6. 對於常規文件,只複製大小小於1M 的文件 # vim /test.sh #!/bin/bash function displayHelp() { echo "Usage: $(basename $0) SRCDIR DSTDIR" } function getSize() { file=$1 size=$(ls -l $file | awk '{print $5}') echo $size } if test $# -ne 2; then displayHelp >&2 exit 1 fi srcdir=$1 dstdir=$2 if test ! -d "$srcdir"; then echo "$srcdir not exists or is not a directory" >&2 exit 1 fi if test ! -e "$dstdir"; then mkdir "$dstdir" fi if test ! -d "$dstdir"; then echo "$dstdir is not a directory" >&2 exit 1 fi for file in $srcdir/* do if test -L $file; then cp -a $file $dstdir/ elif test -f $file; then --------------------------------------------------- size=$(getSize $file) if test "$size" -lt 1048576; then cp -a $file $dstdir/ fi --------------------------------------------------- find $file -type f -size -1024k -exec cp -a {} $dstdir/ \; --------------------------------------------------- fi done