用shell編寫腳本
IT路邊社
前言
與其它的編碼規范一樣,這里所討論的不僅僅是編碼格式美不美觀的問題, 同時也討論一些約定及編碼標准。這份文檔主要側重於我們所普遍遵循的規則,對於那些不是明確強制要求的,我們盡量避免提供意見。
編碼規范對於程序員而言尤為重要,有以下幾個原因:
本文檔中的准則致力於最大限度達到以下原則:
盡管本文檔涵蓋了許多基礎知識,但應注意的是,沒有編碼規范可以為我們回答所有問題,開發人員始終需要再編寫完代碼後,對上述原則做出正確的判斷。
注 :未明確指明的則默認為必須(Mandatory)
主要參考如下文檔:
僅建議Shell用作相對簡單的實用工具或者包裝腳本。因此單個shell腳本內容不宜太過復雜。
在選擇何時使用shell腳本時時應遵循以下原則:
可執行文件不建議有擴展名,庫文件必須使用 .sh 作為擴展名,且應是不可執行的。
執行一個程序時,無需知道其編寫語言,且shell腳本並不要求具有擴展名,所以更傾向可執行文件沒有擴展名。
而庫文件知道其編寫語言十分重要,使用 .sh 作為特定語言後綴的擴展名,可以和其他語言編寫的庫文件加以區分。
文件名要求全部小寫, 可以包含下劃線 _ 或連字元 - , 建議可執行文件使用連字元,庫文件使用下劃線。
正例:
反例:
源文件編碼格式為UTF-8。避免不同操作系統對文件換行處理的方式不同,一律使用 LF 。
每行最多不超過120個字元。每行代碼最大長度限制的根本原因是過長的行會導致閱讀障礙,使得縮進失效。
除了以下兩種情況例外:
如出現長度必須超過120個字元的字元串,應盡量使用here document或者嵌入的換行符等合適的方法使其變短。
示例:
除了在行結束使用換行符,空格是源文件中唯一允許出現的空白字元。
對從來沒有用到的或者被注釋的方法、變數等要堅決從代碼中清理出去,避免過多垃圾造成干擾。
Bash 是唯一被允許使用的可執行腳本shell。
 可執行文件必須以  #!/bin/bash 開始。請使用 set 來設置shell的選項,使得用 bash   echo "Process $: Done making $$$." 
   # 示例7:命令參數及路徑不需要引號  grep -li Hugo /dev/ "$1" 
   # 示例8:常規變數用雙引號,ccs可能為空的特殊情況可不用引號  git send-email --to "${reviewers}" ${ccs:+"--cc" "${ccs}"} 
   # 示例9:正則用單引號,$1可能為空的特殊情況可不用引號  grep -cP '([Ss]pecial||?characters*) ${1:+"$1"} 
   # 示例10:位置參數傳遞推薦帶引號的"$@",所有參數作為單字元串傳遞用帶引號的"$*"  # content of t.sh  func_t {   echo num: $#   echo args: 1:$1 2:$2 3:$3  } 
   func_t "$@"  func_t "$*"  # 當執行 ./t.sh a b c 時輸出如下:  num: 3  args: 1:a 2:b 3:c  num: 1  args: 1:a b c 2: 3: 
使用 $(command) 而不是反引號。
因反引號如果要嵌套則要求用反斜杠轉義內部的反引號。而 $(command) 形式的嵌套無需轉義,且可讀性更高。
正例:
反例:
條件測試
使用 [[ ... ]] ,而不是 [ , test , 和 /usr/bin/[ 。
因為在 [[ 和 ]] 之間不會出現路徑擴展或單詞切分,所以使用 [[ ... ]] 能夠減少犯錯。且 [[ ... ]] 支持正則表達式匹配,而 [ ... ] 不支持。參考以下示例:
盡可能使用變數引用,而非字元串過濾。
Bash可以很好的處理空字元串測試,請使用空/非空字元串測試方法,而不是過濾字元,讓代碼具有更高的可讀性。正例:
反例:
正例:
反例:
正例:
反例:
文件名擴展
當進行文件名的通配符擴展時,請指定明確的路徑。
當目錄中有特殊文件名如以 - 開頭的文件時,使用帶路徑的擴展通配符 ./* 比不帶路徑的 * 要安全很多。
應該避免使用eval。
Eval在用於分配變數時會修改輸入內容,但設置變數的同時並不能檢查這些變數是什麼。反例:
請使用進程替換或者for循環,而不是通過管道連接while循環。
這是因為在管道之後的while循環中,命令是在一個子shell中運行的,因此對變數的修改是不能傳遞給父shell的。
這種管道連接while循環中的隱式子shell使得bug定位非常困難。反例:
如果你確定輸入中不包含空格或者其他特殊符號(通常不是來自用戶輸入),則可以用for循環代替。例如:
使用進程替換可實現重定向輸出,但是請將命令放入顯式子 shell,而非 while 循環創建的隱式子 shell。例如:
總是檢查返回值,且提供有用的返回值。
對於非管道命令,使用 $? 或直接通過 if 語句來檢查以保持其簡潔。
例如:
當內建命令可以完成相同的任務時,在shell內建命令和調用外部命令之間,應盡量選擇內建命令。
因內建命令相比外部命令而言會產生更少的依賴,且多數情況調用內建命令比調用外部命令可以獲得更好的性能(通常外部命令會產生額外的進程開銷)。
正例:
反例:
載入外部庫文件不建議用使用.,建議使用source,已提升可閱讀性。正例:
反例:
除非必要情況,盡量使用單個命令及其參數組合來完成一項任務,而非多個命令加上管道的不必要組合。常見的不建議的用法例如:cat和grep連用過濾字元串; cat和wc連用統計行數; grep和wc連用統計行數等。
正例:
除特殊情況外,幾乎所有函數都不應該使用exit直接退出腳本,而應該使用return進行返回,以便後續邏輯中可以對錯誤進行處理。正例:
反例:
推薦以下工具幫助我們進行代碼的規范:
原文鏈接:http://itxx00.github.io/blog/2020/01/03/shell-standards/
獲取更多的面試題、腳本等運維資料點擊: 運維知識社區 獲取
腳本之---簡訊轟炸機
腳本之---QQ微信轟炸機
ansible---一鍵搭建redis5.0.5集群
elk7.9真集群docker部署文檔
全球最全loki部署及配置文檔
最強安全加固腳本2.0
一鍵設置iptbales腳本
2. shell腳本書寫方法
在shell學習過程中,感覺挺有用的一份比較,略整理分享給大家。
  
 首先,shell的作用
用戶的登陸shell 登陸後默認的shell程序是: /bin/bash
  
 不同的shell內部指令,運行環境會有所區別
  
 常見的shell有
  
 /bin/sh
  
 /bin/bash
  
 /sbin/nologin
  
 1.編寫腳本代碼:
  
 使用vi編輯器,每行一條Linux命令,按照順序執行
  
 2.然後賦予腳本文件可執行的屬性
  
 3.執行腳本文件的三種方法
  
 ./chao.sh
  
 sh /chao.sh
  
 source /chao.sh
  
 更完善的腳本構成
    
 注釋信息
  
 可執行語句
重定向操作
  
  類型 操作符 用途
  
 重定向輸入 < 從指定文件讀取而不是從鍵盤輸入
  
 重定向輸出 > 將輸出文件保存到指定文件(覆蓋原有內容)
  
  >> 將輸出文件保存到指定文件(覆蓋原有內容)
  
 標准錯誤輸出 2> 將錯誤信息保存到指定的文件(覆蓋原有內容)
  
  2>> 將錯誤信息保存到指定的文件
  
 混合輸出 &> 將標准輸出,標准錯誤的內容保存到同一文件中
  
 管道操作符號「|」
  
 將左側的命令輸出結果,作為右側命令的處理對象
shell變數的作用
  
 為靈活管理Linux系統提供的特定參數,有兩層意思
  
 變數名:使用固定的名稱,由系統預設或用戶定義
  
 變數值: 能夠根據用戶設置,系統環境的變化而變化
  
 變數的類型
  
 自定義變數:由用戶自己定義,修改和使用
  
 環境變數: 由系統維護,用於設置工作環境
  
 位置變數: 通過命令行給腳本程序傳遞參數
  
 預定義變數:BASH中內置的一類變數,不能直接修改
  
 定義一個新的變數
  
 格式: 變數名=變數值
  
 變數名以字母或下劃線開頭,區分大小寫,建議全大寫
  
 查看變數的值: echo $變數名
  
 賦值時使用引號:
  
 雙引號:允許使用$符引用其他變數值
  
 單引號: 禁止引用其他變數值,$視為普通字元
  
 反撇號:命令替換,提取命令執行後的輸出結果
  
 將鍵盤輸入內容為變數賦值
  
 格式: read [-p "提示信息"] 變數名
  
 設置變數的作用范圍
  
 export 變數名
  
 export 變數名=變數值
  
 兩種格式可以混合使用
  
 整數變數的運算:
  
 expr 變數1 運算符 變數2 [運算符 變數3]
  
 常見的運算符
  
 加法運算符 +
  
 減法運算符: -
  
 乘法運算符:\*
  
 除法運算符: /
  
 取余運算:%
  
 整數變數的運算(2)
  
 ((變數=變數運算符變數));
  
 等號後面的變數可以是具體數值
  
 例子:
  
 ((a=a+3));
  
 環境變數:
  
 由系統提前創建,用來設置用戶的工作環境
  
 配置文件: /etc/profile ~/.bash_profile
  
 常見環境變數的舉例
位置變數:
  
 表示為$n, n為1~9之間的數字
預定義變數: 
  
 /etc/passwd /etc/shadow
  
 例如一些服務的內置用戶名或密碼
  
 如apache的啟動用戶就是預定義變數
  
 條件測試操作
  
 測試特定的 表達式是否成立,當條件成立時,測試語句的返回值為0,否則為其他數值
  
 格式 : test 條件表達式
應用實例: 
test -z 進行測試的時候 字元串長度為0的時候 結果才返回1
  
  如果變數數值為0 返回0
  
 條件測試操作
  
 [ 操作符 文件或目錄]
[5] 部分是判斷表達式,-d表示判斷是否是目錄
  
 &&是」邏輯與「操作符,只有&&前面的判斷成立,後面的語句才會執行
  
 -b的意思是判斷 後面的路徑是否是一個目錄
  
 echo $? 表示對剛剛執行的表達式進行判斷
  
 0表示成立,1表示不成立
  
 -e filename 如果 filename存在,則為真 [ -e /var/log/syslog ]
  
 -d filename 如果 filename為目錄,則為真 [ -d /tmp/mydir ]
  
 -f filename 如果 filename為常規文件,則為真 [ -f /usr/bin/grep ]
  
 -L filename 如果 filename為符號鏈接,則為真 [ -L /usr/bin/grep ]
  
 -r filename 如果 filename可讀,則為真 [ -r /var/log/syslog ]
  
 -w filename 如果 filename可寫,則為真 [ -w /var/mytmp.txt ]
  
 -x filename 如果 filename可執行,則為真 [ -L /usr/bin/grep ]
  
 filename1-nt filename2 如果 filename1比 filename2新,則為真 [ /tmp/install/etc/services -nt /etc/services ]
  
 filename1-ot filename2 如果 filename1比 filename2舊,則為真 [ /boot/bzImage -ot arch/i386/boot/bzImage ]
  
 字元串比較運算符 (請注意引號的使用,這是防止空格擾亂代碼的好方法)
  
 -z string 如果 string長度為零,則為真 [ -z "$myvar" ]
  
 -n string 如果 string長度非零,則為真 [ -n "$myvar" ]
  
 string1= string2 如果 string1與 string2相同,則為真 [ "$myvar" = "one two three" ]
  
 string1!= string2 如果 string1與 string2不同,則為真 [ "$myvar" != "one two three" ]
  
 算術比較運算符
  
 num1-eq num2 等於 [ 3 -eq $mynum ]
  
 num1-ne num2 不等於 [ 3 -ne $mynum ]
  
 num1-lt num2 小於 [ 3 -lt $mynum ]
  
 num1-le num2 小於或等於 [ 3 -le $mynum ]
  
 num1-gt num2 大於 [ 3 -gt $mynum ]
  
 num1-ge num2 大於或等於 [ 3 -ge $mynum ]
  
 整數值比較
  
 格式: [ 整數1 操作符 整數2 ]
字元串比較
  
 格式1: [ 字元串1 = 字元串2 ]
  
  [ 字元串1 != 字元串2 ]
  
 格式2: [ -z 字元串 ]
邏輯測試:
  
 格式1: [ 表達式1 ] 操作符 [ 表達式2 ]
  
 格式2: 命令1 操作符 命令2
  
 if語句的結構
while語句的語法結構
3. 在Ubuntu下編寫shell腳本讀取文件
需求功能:
                                          
 創建測試用例文件 text :
創建shell腳本:
                                          
 運行結果:
                                          
 利用 awk 'END{print NR}' [文件名] 來輸出行數:
在shell腳本中添加該功能:
                                          
 運行結果:
                                          
 上面的shell文件只是把文件名寫死在腳本中,並沒有實際使用意義,所以需要編寫一個指令來指定需要讀取的文件,就像 vim [文件名] 一樣
  
  「$1」 代表第1個參數,也就是在 read 之後緊跟的參數,將其作為文件名傳入:
將腳本移動至環境變數對應的目錄中:(可以自己更改 /bin/xxx 來決定運行命令的名稱,但注意不能重復)
    sudo mv read /bin/read 
   然後添加運行許可權:
    sudo chmod 755 /bin/read 
  
 打開終端的目錄可以是任何位置,通過以下命令即可運行shell腳本:
    sudo read [文件路徑] 
同理,我們還可以自己為復雜指令編寫shell腳本,來提高命令的使用效率,例如開關ss服務,打開銳捷客戶端認證等等。
4. 怎麼在shell里寫腳本並運行
執行「nano function.sh」命令,創建新的shell腳本文件,名字為「function.sh」。
編輯新創建的shell腳本文件「function.sh"。函數必須先定義後使用。
shell腳本的內容如下:
#!/bin/bash
add(){
sum_1=$1;
sum_2=$2;
sum=`expr $sum_1 + $sum_2`;
echo "the sum is ${sum}";
}
add $1 $2
給新創建的function.sh賦可執行許可權,命令為「chmod 755 function.sh」。
使用「./function.sh 1 2」調用腳本,並給腳本傳遞兩個數字。
6
執行命令的結果為「the sum is 3」。
5. linux上啟動python程序,shell腳本服務怎麼編寫
1.只能夠輸入Python命令。
在Python交互模式下輸入Python代碼,而不要輸入系統的命令。
2.在交互模式下列印語句不是必須的。
在交互模式下不需要輸入完整的列印語句,解釋器自動列印表達式的結果,但是在文件中則需要寫print語句來列印結果。
3.提示符的變換和復合語句。
當在交互模式下輸入兩行或多行的復合語句時,提示符會由>>>變成;如果要結束復合語句的輸入並執行它,那麼必須按下Enter鍵兩次,復合語句才會被執行。
4.交互提示模式一次運行一條語句。
當你想測試某一條命令的時候,交互模式是一個很好的測試方法,輸入然後回車即可猛高大看到執行結果枝豎,非常方便,當然對於復合語句來說,只要最後按兩次Enter鍵即可運行代碼,看到執行結果。
具體如下:
1、簡介
Linux操作系統是基於UNIX操作系統發展而來的一種克隆系統,它誕生於1991年的[Linux桌面]10月5日(這是第一次正式向外公布的時間)。以後藉助於Internet網路,並通過全世界各地計算機愛好者的共同努力,已成為今天世界上使用最多的一種UNIX類操作系統,並且使用人數還在迅猛增長。
2、基本信息
Linux[2]操作系統是UNIX操作系統的一種克隆系統,它誕生linux系統於1991年的10月5日(這是第一次正式向外公布的時間)。以後藉助於Internet網路,並通過全世界各地計算機愛好者的共同努力,已成為今天世界上使用最多的一種UNIX類操作系統,並且使用人數還在迅猛增長。
3、分區規定
設備管理在Linux中,每一個硬體設備都映射到一個系統的文件,對於硬碟、光碟機等,IDE或SCSI設備也不例外。Linux把各種IDE設備分配了一個由hd前綴組成念鋒的文件;而對於各種SCSI設備,則分配了一個由sd前綴組成的文件。
6. 編寫Shell腳本---接受、判斷用戶參數
[TOC]
如果想查看當前所在工作路徑並列出當前目錄下所有的文件及屬性信息,實現這個功能的腳本如下:
 Shell腳本文件的名稱可以任意,但為了避免被誤以為是普通文件,建議將 .sh 後綴加上,以表示是一個腳本文件
   在上面的 example.sh 腳本中出現了三種不同的元素:
執行腳本有兩種方式:
各變數的作用:
用測試語句測試一個文件是否為目錄,然後通過 Shell 解釋器內設 $? 變數顯示上一條命令的返回值
在Shell終端中邏輯「與」的運算符號是 && ,它表示當前面的命令執行成功後才執行後面的命令
等號兩邊必須要有空格,才能進行邏輯等於
它表示把條件測試中的判斷結果取相反值
整數比較運算符僅對數字操作,且不能使用等號、大於號、小於號來判斷。因為等號與賦值命令符沖突,大於號和小於號分別與輸出重定向和輸入重定向命令符沖突。因此一定要使用規范的整數比較運算符進行操作。
示例:使用 free -m 命令查看內存使用量情況(單位MB),然後通過 grep Mem: 命令過濾出剩餘內存量的行,使用 awk'{print $4}' 命令只保留第四列,最後用 FreeMem=`語句` 的方式把語句內執行結果復制給變數
示例1 :判斷String變數是否為空,進而判斷是否定義了這個變數
示例2 :引入邏輯運算符,判斷語系LANG
