編程基礎: 程序:指令+數據 程序編程風格: 過程式:以指令爲中心,數據服務於指令。 小軟件過程,大軟件對象。 對象式:以數據爲中心,指令服務於數據 shell程序:提供了編程能力,解釋執行 shell腳本基礎: shell腳本: 包含一些命令或聲明,並符合必定格式的文本文件 格式要求:首行shebang機制 #!/bin/bash #!/usr/bin/python #!/usr/bin/perl shell腳本的用途有: 自動化經常使用命令 執行系統化管理和故障排除 建立簡單的應用程序 處理文本或文件
建立shell腳本 第一步:使用文本編輯器來建立文本文件 第一行必須包括shell聲明序列:#! #!/bin/bash 添加註釋 註釋以#開頭 第二步:運行腳本 給予執行權限,在命令行上指定腳本的絕對或相對路徑 直接運行解釋器,將腳本做爲解釋器程序的參數運行 腳本規範: 腳本代碼開頭約定: 一、第一行通常爲調用使用的語言 二、程序名,避免更改文件名爲沒法找到正確的文件 三、版本號 四、更改後的時間 五、做者相關信息 六、該程序的做用,及注意事項 七、最後是各版本的更新簡要說明 腳本的基本結構: 腳本的基本結構 #!SHEBANG CONFIGURATON_VARIABLES FUNCTION_DEFINITIONS MAIN_CODE shell腳本示例 #!/bin/bash # ------------------------------------------ # Filename: hello.sh # Revision: 1.1 # Date: 2017/06/01 # Author: wang # Email: wang@gmail.com # Website: www.magedu.com # Description: This is the first script # ------------------------------------------ # Copyright: 2017 wang # License: GPL echo 「hello world」
腳本調試 檢測腳本中的語法錯誤 bash -n /path/to/some_script 調試執行 bash -x /path/to/some_script bash -n 只能檢查語法錯誤
變量 變量:命名的內存空間 數據存儲方式: 字符: 數值:×××,浮點型 變量:變量類型 做用: 一、數據存儲格式 二、參與的運算 三、表示的數據範圍 類型: 字符 數值:×××、浮點型 加" "能夠改變格式 如: echo="name"
變量: 強類型:變量不通過強制轉換,它永遠是這個數據類型,不容許隱式的類型轉 換。通常定義變量時必須制動類型、參與運算必須符合類型要求;調用未聲明 變量會產生錯誤 如 java,c# 弱類型:語言的運行時回隱形作數據類型轉換。無須指定類型,默認均爲字符型; 參與運算會自動進行隱式類型轉換;變量無需事先定義可直接調用 如:bash不支持浮點數,php 能夠用數字可是不能放在前面
變量命名法則: 一、不能使程序中的保留字:列如if,for 二、只能使用數字、字母及下劃線,且不能以數字開頭 三、見名知義 四、統一命名法則:駱峯命名法:把多個首字母大寫,小駝峯:第一個首字母大寫,
bash中變量的種類: 根據變量的生效範圍等標準劃分下面變量類型: 局部變量:生效範圍爲當前shell進程;對當前shell以外的其餘shell進程,包括 當前shell的子shell進程均無效 環境變量:生效範圍爲當前shell進程及其子進程 本地變量:生效範圍爲當前shell進程中某代碼片斷,一般指函數 位置變量:$1,$2,...來表示,用於讓腳本在腳本代碼中調用經過命令行傳遞給它 的參數 特殊變量:$>,$0,$@,$#,$$ 局部變量: echo $$ echo $PPID:父子進程 局部變量只能在當前shell有效 在下級子進程變量不能往上傳別的進程 全局變量:使用要加關鍵字 export :把當前變量轉換環境變量 它容許往下傳 父進程能夠傳給子進程 bash 後臺執行 declare -x 也能夠生成全部環境變量 env也能顯示環境變量 unset name 刪除當前環境變量 set :本劇變量 全局變量都有 常量:固定值 readonly -p:顯示常量 ():用於一次性任務 執行一個小subsheell 不影響環境, {}:和小括號有區別 位置變量:能讓腳本寫死 $1 $2 $3 1 存的就是第一個字符串 10 個以上就得用{} 如:e'cho "ALL args are {$10}" scp :能夠遠程複製 scp.sh shift:從右往左擠掉 ping -c:指定網絡拼一次
總結: shell 變量:局部和環境 $1,$@ $*,$#,$0 set unset exprot declare -i -r -x env 環境變量: 變量聲明、賦值: export name=VALUE declare -x name=VALUE 變量引用:$name,${name} 顯示全部環境變量: env printenv export declare -x 刪除變量: unset name
環境變量: bash內建的環境變量: PATH SHELL UID USER HOME PWD SHLVL LANG MAIL HOSTNAME HISTSIZE —:下劃線 只讀和位置變量: 只讀變量:只能聲明,但不能修改和刪除 聲明只讀變量: readonly name declare -r name 查看只讀變量: readonly -p 位置變量:在腳本代碼中調用命令行傳遞給腳本的參數 $1,$2,...:對應第1,第2等參數,shift [n]換位置 $0:命令自己 $*;傳遞給腳本的全部參數,所有參數合爲一個字符串 $@:傳遞給腳本的全部參數,每一個參數爲獨立字符串 $#:傳遞給腳本的參數的個數 $@$*只在被雙引號抱起來的時候纔會有差別 set -- 清空全部位置變量
退出狀態: 進程使用退出狀態來報告成功或失敗 0表明成功,1 - 255表明失敗 $?:變量保存最近的命令退出狀態 列如: ping -c1 -w1 hostdown &>/dev/null echo$? 退出狀態碼: bash自定義退出狀態碼 exit[n]:自定義退出狀態碼 注意:腳本中一旦遇到exit命令,腳本會當即終止;終止退出狀態取決於exit命 令後面的數字 注意:若是未給腳本指定退出狀態碼,整個腳本的退出狀態碼取決於腳本中執行 的最後一條命令的狀態碼 算數運算: bash中的算數運算:help let +,-,*,%取模(取餘),**(乘方) 實現算數運算: 一、let var=算數表達式 二、var=$[算數表達式] 三、var=$((算數表達式)) 四、var=$(expr arg1 arg2 arg3...) 五、declare -i var =數值 六、echo '算數表達式' | bc 乘法符號有些場景中須要轉義,如* bash有內建的隨機數生成器:$RANDOM(0-32767) echo $[$RANDOM%50】 :0-49之間隨機數
賦值: 加強型賦值: +=,-=,*=,/=,%= let varOPERvare 列如:let count+=3 自加3後減值 自增,自減: let var+=1 let var++ let var-=1 let var--
邏輯運算; true,false 1,0 與: 1與1=1 & 而且 and 1與0=0 | 或者 or 0與1=0 cmd1 && cmd2 若是cmd1爲假,cmd2不須要執行,反之cmd1爲真,須要cmd2執行 0與0=0 cmd1 || cmd2若是爲真,cmd2不須要執行,反之cmd1爲假,須要cmd2執行 或: XOR 異或 1或1=1 0^1=1 1或0=1 0^0=0 0或1=1 1^0=1 0或0=0 1^1=0 邏輯運算: 非:! !1=0 !0=1 短路運算: 短路與 第一個爲0,結果一定爲0 第一個爲1,第二個必需要參與運算 短路或 第一個爲1,結果一定爲1 第一個爲0,第二個必需要參與運算 異或:^ 異或的兩個值,相同爲假,沒必要爲真
條件測試; 判斷某需求是否知足,須要由測試機制來實現 專用的測試表達式須要由測試命令輔助完成測試過程 評估布爾聲明,以便用條件執行中 若真,澤返回0 若假,則返回1 測試命令: testEXPRESSION [ EXPRESSION] [[ EXPRESSION]] 注意:EXPRESSUON先後必須有空白字符 條件性的執行操做符: 根據退出狀態而定,命令能夠有條件地運行 &&表明條件行的AN 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" bash的數值測試 -v VAR 變量VAR是否設置 數值測試: -gt 是否大於 -ge 是否大於等於 -eq 是否等於 -ne 是否不等於 -lt 是否小於 -le 是否小於等於 bash的字符串測試 字符串測試: == 是否等於 > ascii碼是否大於ascii碼 < 是否小於 != 是否不等於 =~ 左側字符串是否可以被右側的PATTERN所匹配 注意: 此表達式通常用於[[ ]]中;擴展的正則表達式 -z "STRING「 字符串是否爲空,空爲真,不空爲假 -n "STRING「 字符串是否不空,不空爲真,空爲假 注意:用於字符串比較時的用到的操做數都應該使用引號
Bash的文件測試 存在性測試 -a FILE:同-e -e FILE: 文件存在性測試,存在爲真,不然爲假 存在性及類別測試 -b FILE:是否存在且爲塊設備文件 -c FILE:是否存在且爲字符設備文件 -d FILE:是否存在且爲目錄文件 -f FILE:是否存在且爲普通文件 -h FILE 或 -L FILE:存在且爲符號連接文件 -p FILE:是否存在且爲命名管道文件 -S FILE:是否存在且爲套接字文件 Bash的文件權限測試 文件權限測試: -r FILE:是否存在且可讀 -w FILE: 是否存在且可寫 -x FILE: 是否存在且可執行 文件特殊權限測試: -u FILE:是否存在且擁有suid權限 -g FILE:是否存在且擁有sgid權限 -k FILE:是否存在且擁有sticky權限 Bash的文件屬性測試 文件大小測試: -s FILE: 是否存在且非空 文件是否打開: -t fd: fd 文件描述符是否在某終端已經打開 -N FILE:文件自從上一次被讀取以後是否被修改過 -O FILE:當前有效用戶是否爲文件屬主 -G FILE:當前有效用戶是否爲文件屬組 Bash的文件屬性測試 雙目測試: 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如何展開命令行 把命令行分紅單個命令詞 展開別名 展開大括號的聲明({}) 展開波浪符聲明(~) 命令替換$() 和 ``) 再次把命令行分紅命令詞 展開文件通配(*、?、[abc]等等) 準備I/0重導向(<、>) 運行命令 防止擴展 反斜線(\)會使隨後的字符按原意解釋 $ echo Your cost: \$5.00 Your cost: $5.00 加引號來防止擴展 • 單引號(’)防止全部擴展 • 雙引號(」)也防止全部擴展,可是如下狀況例外: $(美圓符號) - 變量擴展 `(反引號) - 命令替換 \(反斜線) - 禁止單個字符擴展 !(歎號) - 歷史命令替換 bash的配置文件 按生效範圍劃分,存在兩類: 全局配置: /etc/profile /etc/profile.d/*.sh /etc/bashrc 我的配置: ~/.bash_profile ~/.bashrc bashrc bash run command source 這種寫法在當前腳本中運行 通常配置文件用source 變量普通腳本是不能支持別名的 10:16 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 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 個歷史命令 read x y z <<< "i j k" echo $. 9:42 49 11:34 如何判斷命令是否存在? which mkisofs >& /dev/null if [ "$?" != 0 ] ; then echo "mkisofs Not Found" echo "yum install mkisofs" fi 判斷文件是否存在? if [ -f $2 ]; then echo "....." exit 1 fi test(選項) 選項 -b<文件>:若是文件爲一個塊特殊文件,則爲真; -c<文件>:若是文件爲一個字符特殊文件,則爲真; -d<文件>:若是文件爲一個目錄,則爲真; -e<文件>:若是文件存在,則爲真; -f<文件>:若是文件爲一個普通文件,則爲真; -g<文件>:若是設置了文件的SGID位,則爲真; -G<文件>:若是文件存在且歸該組全部,則爲真; -k<文件>:若是設置了文件的粘着位,則爲真; -O<文件>:若是文件存在而且歸該用戶全部,則爲真; -p<文件>:若是文件爲一個命名管道,則爲真; -r<文件>:若是文件可讀,則爲真; -s<文件>:若是文件的長度不爲零,則爲真; -S<文件>:若是文件爲一個套接字特殊文件,則爲真; -u<文件>:若是設置了文件的SUID位,則爲真; -w<文件>:若是文件可寫,則爲真; -x<文件>:若是文件可執行,則爲真。 實例 linux中shell編程中的test常見用法: 判斷表達式 if test #表達式爲真 if test ! #表達式爲假 test 表達式1 –a 表達式2 #兩個表達式都爲真 test 表達式1 –o 表達式2 #兩個表達式有一個爲真 test 表達式1 ! 表達式2 #條件求反 判斷字符串 test –n 字符串 #字符串的長度非零 test –z 字符串 #字符串的長度是否爲零 test 字符串1=字符串2 #字符串是否相等,若相等返回true test 字符串1!=字符串2 #字符串是否不等,若不等反悔false 判斷整數 test 整數1 -eq 整數2 #整數相等 test 整數1 -ge 整數2 #整數1大於等於整數2 test 整數1 -gt 整數2 #整數1大於整數2 test 整數1 -le 整數2 #整數1小於等於整數2 test 整數1 -lt 整數2 #整數1小於整數2 test 整數1 -ne 整數2 #整數1不等於整數2 判斷文件 test File1 –ef File2 兩個文件是否爲同一個文件,可用於硬鏈接。主要判斷兩個文件是否指向同一個inode。 test File1 –nt File2 判斷文件1是否比文件2新 test File1 –ot File2 判斷文件1比是否文件2舊 test –b file #文件是否塊設備文件 test –c File #文件而且是字符設備文件 test –d File #文件而且是目錄 test –e File #文件是否存在 (經常使用) test –f File #文件是否爲正規文件 (經常使用) test –g File #文件是不是設置了組id test –G File #文件屬於的有效組ID test –h File #文件是不是一個符號連接(同-L) test –k File #文件是否設置了Sticky bit位 test –b File #文件存在而且是塊設備文件 test –L File #文件是不是一個符號連接(同-h) test –o File #文件的屬於有效用戶ID test –p File #文件是一個命名管道 test –r File #文件是否可讀 test –s File #文件是不是非空白文件 test –t FD #文件描述符是在一個終端打開的 test –u File #文件存在而且設置了它的set-user-id位 test –w File #文件是否存在並可寫 test –x File #文件屬否存在並可執行 expr用法 expr命令通常用於整數值,但也可用於字符串。通常格式爲: #expr argument operator argument expr也是一個手工命令行計數器。 #$expr 10 + 10 20 #$expr 1500 + 900 2500 #$expr 30 / 3 10 #$expr 30 / 3 / 2 5 (注意運算符左右都有空格) 使用乘號時,必須用反斜線屏蔽其特定含義。由於shell可能會誤解顯示星號的意義。 #$expr 30 * 3 90 17.5.1 增量計數 expr在循環中用於增量計算。首先,循環初始化爲0,而後循環值加1,反引號的用法意 即替代命令。最基本的一種是從(expr)命令接受輸出並將之放入循環變量。 $LOOP=0 #$LOOP=`expr $LOOP + 1` 17.5.2 數值測試 能夠用expr測試一個數。若是試圖計算非整數,將返回錯誤。 $rr=1.1 #$expr $rr + 1 #expr: non-numeric argument $rr=2 $expr $rr + 1 3 (注意:這個例子與原文不一樣) 這裏須要將一個值賦予變量(無論其內容如何),進行數值運算,並將輸出導入dev/null, 而後測試最後命令狀態,若是爲0,證實這是一個數,其餘則代表爲非數值。 $value=12 #$expr $value + 10 > /dev/null 2>&1 $echo $? 0 這是一個數。 $value=hello #$expr $value + 10 > /dev/null 2>&1 $echo $? 2 這是一個非數值字符。 expr也能夠返回其自己的退出狀態,不幸的是返回值與系統最後退出命令恰好相反,成功返回1,任何其餘值爲無效或錯誤。下面的例子測試兩個字符串是否相等,這裏字符串爲「hello」和「hello」。 $value=hello $expr $value = "hello" 1 $echo $? 0 expr返回1。不要混淆了,這代表成功。如今檢驗其最後退出狀態,返回0表示測試成功, 「hello」確實等於「hello」。 17.5.3 模式匹配 expr也有模式匹配功能。可使用expr經過指定冒號選項計算字符串中字符數。.*意即任何字符重複0次或屢次。 $value=accounts.doc $expr $value : '.*' 12 在expr中可使用字符串匹配操做,這裏使用模式. d o c抽取文件附屬名。 $expr $value : '(.*).doc' accounts