1. 程式人生 > >bash指令碼程式設計基礎

bash指令碼程式設計基礎

1.1.1 為什麼學Shell

Shell指令碼語言是實現Linux/UNIX系統管理及自動化運維所必備的重要工具, Linux/UNIX系統的底層及基礎應用軟體的核心大都涉及Shell指令碼的內容。每一個合格 的Linux系統管理員或運維工程師,都需要能夠熟練地編寫Shell指令碼語言,並能夠閱 讀系統及各類軟體附帶的Shell指令碼內容。只有這樣才能提升運維人員的工作效率,適 應曰益複雜的工作環境,減少不必要的重複工作,從而為個人的職場發展奠定較好的基礎

1.1.2 什麼是shell

Shell是一個命令直譯器,它在作業系統的最外層,負責直接與使用者對話,把使用者的輸入解釋給作業系統,並處理各種各樣的作業系統的輸出結果,輸出螢幕返回給使用者。

這種對話方式可以是:

互動的方式:從鍵盤輸入命令,通過/bin/bash的解析,可以立即得到Shell的迴應

[[email protected] ~]# ls            
anaconda-ks.cfg  
[[email protected] ~]# echo ls |bash 
anaconda-ks.cfg   

非互動的方式: 指令碼

1.1.3 什麼是Shell指令碼

  命令、變數和流程控制語句等有機的結合起來

         shell指令碼擅長處理純文字型別的資料,而linux中,幾乎所有的配置檔案,日誌,都是純文字型別檔案

1.1.4 指令碼語言的種類

一、編譯型語言

定義:指用專用的編譯器,針對特定的操作平臺(作業系統)將某種高階語言原始碼一次性翻譯成可被硬體平臺直接執行的二進位制機器碼(具有運算元,指令、及相應的格式),這個過程叫做編譯(./configure  make makeinstall );編譯好的可執行性檔案(.exe),可在相對應的平臺上執行(移植性差,但執行效率高)。。

典型的編譯型語言有, C語言、C++等。

另外,Java語言是一門很特殊的語言,Java程式需要進行編譯步驟,但並不會生成特定平臺的二進位制機器碼,它編譯後生成的是一種與平臺無關的位元組碼檔案(*.class)(移植性好的原因),這種位元組碼自然不能被平臺直接執行,執行時需要由直譯器解釋成相應平臺的二進位制機器碼檔案;大多數人認為Java是一種編譯型語言,但我們說Java即是編譯型語言,也是解釋型語言也並沒有錯。

二、解釋型語言

定義:指用專門直譯器對源程式逐行解釋成特定平臺的機器碼並立即執行的語言;相當於把編譯型語言的編譯連結過程混到一起同時完成的。

解釋型語言執行效率較低,且不能脫離直譯器執行,但它的跨平臺型比較容易,只需提供特定直譯器即可。

常見的解釋型語言有, Python(同時是指令碼語言)與Ruby等。

三、指令碼語言

定義:為了縮短傳統的編寫-編譯-連結-執行(edit-compile-link-run)過程而建立的計算機程式語言。

特點:程式程式碼即是最終的執行檔案,只是這個過程需要直譯器的參與,所以說指令碼語言與解釋型語言有很大的聯絡。指令碼語言通常是被解釋執行的,而且程式是文字檔案。

典型的指令碼語言有,JavaScript,Python,shell等。

其他常用的指令碼語句種類

PHP是網頁程式,也是指令碼語言。是一款更專注於web頁面開發(前端展示)的指令碼語言,例如:Dedecms,discuz。PHP程式也可以處理系統日誌,配置檔案等,php也可以呼叫系統命令。

Perl指令碼語言。比shell指令碼強大很多,語法靈活、複雜,實現方式很多,不易讀,團隊協作困難,但仍不失為很好的指令碼語言,存世大量的程式軟體。MHA高可用Perl寫的

Python,不但可以做指令碼程式開發,也可以實現web程式以及軟體的開發。近兩年越來越多的公司都會要求會Python。

Shell指令碼與php/perl/python語言的區別和優勢?

shell指令碼的優勢在於處理作業系統底層的業務 (linux系統內部的應用都是shell指令碼完成)因為有大量的linux系統命令為它做支撐。2000多個命令都是shell指令碼程式設計的有力支撐,特別是grep、awk、sed等。例如:一鍵軟體安裝、優化、監控報警指令碼,常規的業務應用,shell開發更簡單快速,符合運維的簡單、易用、高效原則.

  PHP、Python優勢在於開發運維工具以及web介面的管理工具,web業務的開發等。處理一鍵軟體安裝、優化,報警指令碼。常規業務的應用等php/python也是能夠做到的。但是開發效率和複雜比用shell就差很多了。

系統環境說明

[[email protected] scripts]# cat /etc/redhat-release  #檢視當前版本
CentOS Linux release 7.4.1708 (Core) 
[[email protected] scripts]# uname -r   #檢視當前核心版本
3.10.0-693.el7.x86_64
[[email protected] scripts]# getenforce   #使用getenforce命令可以顯示當前SELinux的應用模式,是強制、執行還是停用。98
Disabled
[[email protected] scripts]# systemctl status firewalld.service  #檢視當前防火牆狀態
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
   Active: inactive (dead)
     Docs: man:firewalld(1)

                     補充:<Linux系統uname命令用法>

                              uname命令:作業系統資訊的顯示

                              uname 命令主要用於顯示作業系統的資訊,包括版本、平臺的資訊。

                                它的引數主要有以下:

                                        -a 顯示全部資訊

                                        -s 顯示核心名稱

                                        -n 顯示主機名

                                        -r 顯示當前系統的核心版本

                                        -m 顯示主機的硬體名稱

                                        -p 顯示處理器的型別

                                        -i 顯示主機的硬體平臺

                                       -o 顯示所使用的作業系統的名稱

                             擴充套件:[[email protected] ~]# getconf LONG_BIT  //檢視當前系統為32位

                                        [[email protected] ~]# cat /etc/issue    //檢視當前系統的型別

1.1.5 系統中的shell

檢視系統中的命直譯器

[[email protected] ~]# cat /etc/shells   #顯示系統擁有的shell
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin

常用作業系統的預設shell

1.Linux是Bourne Again shell(bash)

2.Solaris和FreeBSD預設的是Bourne shell(sh)

3.AIX下是Korn Shell(ksh)

4.HP-UX預設的是POSIX shell(sh)

[[email protected] ~]# echo $SHELL  #顯示當前預設sell
/bin/bash

bash版本

[[email protected] scripts]# bash -version  #顯示當前shell版本
GNU bash, 版本 4.2.46(2)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
許可證 GPLv3+: GNU GPL 許可證版本3或者更高 <http://gnu.org/licenses/gpl.html>

這是自由軟體,您可以自由地更改和重新發布。
在法律允許的範圍內沒有擔保. 

1.2 指令碼書寫規範

1.2.1 指令碼統一存放目錄

[[email protected] ~]# mkdir -p /server/scripts/
[[email protected] ~]# cd /server/scripts/

1.2.2 選擇直譯器

注意格式 ↓

其中開頭的"#!"字元又稱為幻數,在執行bash指令碼的時候,核心會根據"#!"後的直譯器來確定該用那個程式解釋這個指令碼中的內容。

[[email protected] scripts]# head -1 /etc/init.d/*
==> /etc/init.d/functions <==
# -*-Shell-script-*-

==> /etc/init.d/netconsole <==
#!/bin/bash

==> /etc/init.d/network <==
#! /bin/bash

1.2.3 編輯指令碼使用vim

使用 .vimrc 檔案,能夠快速的生成開頭的註釋資訊

[[email protected] scripts]# cat  ~/.vimrc 
autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call SetTitle()"

func SetTitle()
    if expand("%:e") == 'sh'
        call setline(1,"#!/bin/bash")
        call setline(2, "##############################################################")
        call setline(3, "# File Name: ".expand("%"))
        call setline(4, "# Version: V1.0")
        call setline(5, "# Author: clsn")
        call setline(6, "# Organization: http://blog.znix.top")
        call setline(7, "# Created Time : ".strftime("%F %T"))
        call setline(8, "# Description:")
        call setline(9, "##############################################################")
        call setline(10, "")
    endif
endfunc

使用後的效果

[[email protected] scripts]# cat  scripts_test.sh 
#!/bin/bash
##############################################################
# File Name: scripts_test.sh
# Version: V1.0
# Author: clsn
# Organization: http://blog.znix.top
# Created Time : 2017-12-04 11:39:57
# Description:  First scripts file
##############################################################

在Shell指令碼中,跟在#後面的內容表示註釋。註釋部分不會被執行,僅給人看。註釋可以自成一行,也可以跟在命令後面,與命令同行。要養成寫註釋的習慣,方便自己與他人。

最好不用中文註釋,因為在不同字符集的系統會出現亂碼。(字符集為zh_CN.UTF-8,為中文)。

1.2.4 檔名規範

         名字要有意義,並且結尾以 .sh 結束

1.2.5 開發的規範和習慣小結

1) 放在統一的目錄

2) 指令碼以.sh為副檔名

3) 開頭指定指令碼直譯器。

4) 開頭加版本版權等資訊,可配置~/.vimrc檔案自動新增。

5) 指令碼不要用中文註釋,儘量用英文註釋。

6) 程式碼書寫優秀習慣

  a、成對的內容一次性寫出來,防止遺漏,如[  ]、' '、" "等

  b、[  ]兩端要有空格,先輸入[  ],退格,輸入2個空格,再退格寫。

  c、流程控制語句一次書寫完,再新增內容。(if 條件 ; then  內容;fi)ddd

  d、通過縮排讓程式碼易讀。

  f、指令碼中的引號都是英文狀態下的引號,其他字元也是英文狀態。

1.3 shell指令碼的執行

1.3.1 執行指令碼的辦法

sh/bash   scripts.sh 
chown +x   ./scripts.sh  && ./scripts.sh  
source scripts.sh
. (空格) scripts.sh
cat oldboyedu.sh |bash  # 效率較低

source 與 . (點) 的作用

soucre命令

[[email protected] ~]# help source  |head -2
source: source 檔名 [引數]
    在當前 shell 中執行一個檔案中的命令。

. (點)

[[email protected] scripts]# help . |head -2
.: . 檔名 [引數]
    在當前 shell 中執行一個檔案中的命令。

1.3.2 sh 於 source的區別

[[email protected] scripts]# sh  clsn_test.sh 
Hello World!
[[email protected] scripts]# echo $clsn
#  sh  新建一個Shell視窗(新建一個程序)執行一個檔案中的命令。

[[email protected] scripts]# source clsn_test.sh 
Hello World!
[[email protected] scripts]# echo $clsn
Hello World!

補充:

Linux中執行 .sh 的方法
複製程式碼
linux下執行.sh檔案的方法
   .sh檔案就是文字檔案,如果要執行,需要使用chmod a+x xxx.sh來給可執行許可權。  
   
   是bash指令碼麼
  可以用touch test.sh #建立test.sh檔案
  vi test.sh #編輯test.sh檔案
  加入內容
  #!/bin/bash
   mkdir test
   儲存退出。
  chmod a+x test.sh #給test.sh可執行許可權
  如test,sh檔案在 /home/work檔案下
  執行
  方法一 本身目錄下執行
  進入 cd /home/workwen檔案下
  執行 ./test.sh
   命令會在當前目錄下建立一個“test”目錄。
  方法二 絕對路勁執行
  執行 /home/work/test.sh  
  方法三 本身目錄下執行
  sh test.sh 
   最後建議:使用
  
   C程式碼 
  1.man sh    
   man sh 來看看sh 的介紹~


Linux.sh語法


介紹:
1 開頭
 程式必須以下面的行開始(必須方在檔案的第一行):
#!/bin/sh
  符號#!用來告訴系統它後面的引數是用來執行該檔案的程式。在這個例子中我們使用/bin/sh來執行程式。
 當編寫指令碼完成時,如果要執行該指令碼,還必須使其可執行。
 要使編寫指令碼可執行:
 編譯 chmod +x filename 這樣才能用./filename 來執行
2 註釋
 在進行shell程式設計時,以#開頭的句子表示註釋,直到這一行的結束。我們真誠地建議您在程式中使用註釋。
 如果您使用了註釋,那麼即使相當長的時間內沒有使用該指令碼,您也能在很短的時間內明白該指令碼的作用及工作原理。
3 變數
 在其他程式語言中您必須使用變數。在shell程式設計中,所有的變數都由字串組成,並且您不需要對變數進行宣告。要賦值給一個變數,您可以這樣寫:
#!/bin/sh
  #對變數賦值:
 a=”hello world”
# 現在列印變數a的內容:
 echo “A is:”
 echo $a
有時候變數名很容易與其他文字混淆,比如:
 num=2
  echo “this is the $numnd”
 這並不會打印出”this is the 2nd”,而僅僅列印”this is the “,因為shell會去搜索變數numnd的值,但是這個變數時沒有值的。可以使用花括號來告訴shell我們要列印的是num變數:
 num=2
  echo “this is the ${num}nd”
 這將列印: this is the 2nd
 4 環境變數
 由export關鍵字處理過的變數叫做環境變數。我們不對環境變數進行討論,因為通常情況下僅僅在登入指令碼中使用環境變數。
5 Shell命令和流程控制
 在shell指令碼中可以使用三類命令:
1)Unix 命令:
  雖然在shell指令碼中可以使用任意的unix命令,但是還是由一些相對更常用的命令。這些命令通常是用來進行檔案和文字操作的。
 常用命令語法及功能
 echo “some text”: 將文字內容列印在螢幕上
 ls: 檔案列表
 wc –l filewc -w filewc -c file: 計算檔案行數計算檔案中的單詞數計算檔案中的字元數
 cp sourcefile destfile: 檔案拷貝
 mv oldname newname : 重新命名檔案或移動檔案
 rm file: 刪除檔案
 grep ‘pattern’ file: 在檔案內搜尋字串比如:grep ’searchstring’ file.txt
  cut -b colnum file: 指定欲顯示的檔案內容範圍,並將它們輸出到標準輸出裝置比如:輸出每行第5個到第9個字元cut -b5-9 file.txt千萬不要和cat命令混淆,
 這是兩個完全不同的命令
 cat file.txt: 輸出檔案內容到標準輸出裝置(螢幕)上
 file somefile: 得到檔案型別
 read var: 提示使用者輸入,並將輸入賦值給變數
 sort file.txt: 對file.txt檔案中的行進行排序
 uniq: 刪除文字檔案中出現的行列比如: sort file.txt | uniq
  expr: 進行數學運算Example: add 2 and 3expr 2 “+” 3
  find: 搜尋檔案比如:根據檔名搜尋find . -name filename -print
  tee: 將資料輸出到標準輸出裝置(螢幕) 和檔案比如:somecommand | tee outfile
  basename file: 返回不包含路徑的檔名比如: basename /bin/tux將返回 tux
  dirname file: 返回檔案所在路徑比如:dirname /bin/tux將返回 /bin
  head file: 列印文字檔案開頭幾行
 tail file : 列印文字檔案末尾幾行
 sed: Sed是一個基本的查詢替換程式。可以從標準輸入(比如命令管道)讀入文字,並將
 結果輸出到標準輸出(螢幕)。該命令採用正則表示式(見參考)進行搜尋。不要和shell中的萬用字元相混淆。比如:將linuxfocus替換為 LinuxFocus :cat text.file | sed ’s/linuxfocus/LinuxFocus/’ >newtext.fileawk: awk 用來從文字檔案中提取欄位。預設地,欄位分割符是空格,可以使用-F指定其他分割符。
 catfile.txt | awk -F, ‘{print $1 “,” $3}’這裡我們使用,作為欄位分割符,同時列印第一個和第三個欄位。如果該檔案內容如下: Adam Bor, 34, IndiaKerryMiller, 22, USA命令輸出結果為:Adam Bor, IndiaKerry Miller, USA
 2) 概念: 管道, 重定向和 backtick
  這些不是系統命令,但是他們真的很重要。
 管道 (|) 將一個命令的輸出作為另外一個命令的輸入。
 grep “hello” file.txt | wc -l
  在file.txt中搜索包含有”hello”的行並計算其行數。
 在這裡grep命令的輸出作為wc命令的輸入。當然您可以使用多個命令。
 重定向:將命令的結果輸出到檔案,而不是標準輸出(螢幕)。
 > 寫入檔案並覆蓋舊檔案
 >> 加到檔案的尾部,保留舊檔案內容。
 反短斜線
 使用反短斜線可以將一個命令的輸出作為另外一個命令的一個命令列引數。
 命令:
 find . -mtime -1 -type f -print
  用來查詢過去24小時(-mtime –2則表示過去48小時)內修改過的檔案。如果您想將所有查詢到的檔案打一個包,則可以使用以下linux 指令碼:
 #!/bin/sh
  # The ticks are backticks (`) not normal quotes (‘):
  tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`
 3) 流程控制
 1.if
  “if” 表示式 如果條件為真則執行then後面的部分:
 if ….; then
  ….
  elif ….; then
  ….
  else
  ….
  fi
  大多數情況下,可以使用測試命令來對條件進行測試。比如可以比較字串、判斷檔案是否存在及是否可讀等等…
 通常用” [ ] “來表示條件測試。注意這裡的空格很重要。要確保方括號的空格。
 [ -f "somefile" ] :判斷是否是一個檔案
 [ -x "/bin/ls" ] :判斷/bin/ls是否存在並有可執行許可權
 [ -n "$var" ] :判斷$var變數是否有值
 [ "$a" = "$b" ] :判斷$a和$b是否相等
 執行man test可以檢視所有測試表達式可以比較和判斷的型別。
 直接執行以下指令碼:
 #!/bin/sh
  if [ "$SHELL" = "/bin/bash" ]; then
  echo “your login shell is the bash (bourne again shell)”
 else
  echo “your login shell is not bash but $SHELL”
 fi
  變數$SHELL包含了登入shell的名稱,我們和/bin/bash進行了比較。
 快捷操作符