日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Shell脚本编程详解

發(fā)布時(shí)間:2024/1/23 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Shell脚本编程详解 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 前置知識(shí)
      • shell變量
          • 環(huán)境變量
          • 本地變量
      • shell腳本執(zhí)行方式
  • 基本語(yǔ)法
      • 通配符
      • 命令代換
      • 算數(shù)代換
      • 轉(zhuǎn)義字符
      • 字符串符號(hào)
      • 邏輯運(yùn)算
  • 腳本語(yǔ)法
      • 條件測(cè)試
      • 流程控制
      • 位置參數(shù)
      • 函數(shù)
      • 腳本調(diào)試
  • 實(shí)例
      • 開(kāi)機(jī)自動(dòng)腳本
      • 登陸自動(dòng)腳本
  • 字符串處理
      • 基本操作
      • 字符串截取
          • 字符截取
          • 子串截取
      • 字符串替換
      • 大小寫(xiě)轉(zhuǎn)換
  • 數(shù)組
      • 普通數(shù)組
      • 關(guān)聯(lián)數(shù)組
  • 注意事項(xiàng)

前置知識(shí)

shell變量

??按照慣例,Shell變量由全大寫(xiě)字母加下劃線組成,有兩種類型的Shell變量:

環(huán)境變量

??環(huán)境變量可以從父進(jìn)程傳給子進(jìn)程,因此Shell進(jìn)程的環(huán)境變量可以從當(dāng)前Shell進(jìn)程傳給fork出來(lái)的子進(jìn)程。

$ env # 打印系統(tǒng)環(huán)境變量 $ printenv # 打印系統(tǒng)環(huán)境變量 $ echo $PATH # PATH環(huán)境變量

??實(shí)際應(yīng)用中比較常用的是設(shè)置(PATH)環(huán)境變量:

  • 對(duì)所有用戶永久生效

    $ vim /etc/profile $ export CLASSPATH=./JAVA_HOME/lib; $ export PATH=/usr/local/bin:$PATH
  • 僅對(duì)當(dāng)前終端有效

    $ export PATH=/usr/local/bin:$PATH
  • 對(duì)某一用戶永久有效

    $ vim ~/.bashrc $ export PATH=/usr/local/bin:$PATH
本地變量

??只存在于當(dāng)前Shell進(jìn)程,用set命令可以顯示當(dāng)前Shell進(jìn)程中定義的所有變量(包括本地變量和環(huán)境變量)和函數(shù)。環(huán)境變量是任何進(jìn)程都有的概念,而本地變量是Shell特有的概念。

$ VAR=value # 等號(hào)左右兩邊不要有空格,否則會(huì)被Shell解釋成命令和命令行參數(shù) $ echo $VAR $ echo ${VAR} $ $VAR # 特別注意這種方式會(huì)當(dāng)作命令行來(lái)執(zhí)行 >value: command not found$ unset VAR # 刪除已定義的環(huán)境變量或本地變量

??一個(gè)變量定義后僅存在于當(dāng)前Shell進(jìn)程,它是本地變量,用export命令可以把本地變量導(dǎo)出為環(huán)境變量,定義和導(dǎo)出環(huán)境變量通常可以一步完成。

$ export VARNAME=value

shell腳本執(zhí)行方式

# assume a script like below # test.sh cd docker_test ls
  • ./test.sh

    chmod a+x test.sh ./test.sh

??Shell會(huì)fork一個(gè)子進(jìn)程并調(diào)用exec執(zhí)行./test.sh這個(gè)程序,exec系統(tǒng)調(diào)用應(yīng)該把子進(jìn)程的代碼段替換成./test.sh程序的代碼段,并從它的_start開(kāi)始執(zhí)行。然而test.sh是個(gè)文本文件,根本沒(méi)有代碼段和_start函數(shù),怎么辦呢?其實(shí)exec還有另外一種機(jī)制,如果要執(zhí)行的是一個(gè)文本文件,并且第一行用Shebang指定了解釋器,則用解釋器程序的代碼段替換當(dāng)前進(jìn)程,并且從解釋器的_start開(kāi)始執(zhí)行,而這個(gè)文本文件被當(dāng)作命令行參數(shù)傳給解釋器。

  • /bin/bash ./test.sh

    這種執(zhí)行方式和上一種效果相同,都不會(huì)影響交互環(huán)境,且不需要test.sh文件具有可執(zhí)行權(quán)限。

  • source ./test.sh

    這種執(zhí)行方式直接在交互式Shell下執(zhí)行的,會(huì)改變交互式Shell的環(huán)境。

  • . ./test.sh

??這種執(zhí)行方式直接在交互式Shell下執(zhí)行的,會(huì)改變交互式Shell的環(huán)境。

小結(jié): (cd ./docker_test;ls -l)相當(dāng)于前兩種方式,去掉括號(hào)相當(dāng)于后兩種方式

基本語(yǔ)法

通配符

??通配符(Wildcard)常用于腳本或平常的命令行之中,需要注意的就是所匹配的文件名是由Shell展開(kāi)的,也就是說(shuō)在參數(shù)還沒(méi)傳給程序之前已經(jīng)展開(kāi)了。

# * 匹配0個(gè)或多個(gè)任意字符 # ? 匹配一個(gè)任意字符 # [若干字符] 匹配方括號(hào)中任意一個(gè)字符的一次出現(xiàn)$ ls /dev/ttyS* $ ls ch0?.doc $ ls ch0[0-2].doc $ ls ch[012] [0-9].doc

命令代換

??由' '反引號(hào)括起來(lái)的是一條命令,Shell先執(zhí)行該命令,然后將輸出結(jié)果立刻代換到當(dāng)前命令行中。

$ DATE=`date` $ echo $DATE# 命令代換也可以使用$() $ DATE=$(date)

算數(shù)代換

??算術(shù)代換是指,$(())中的Shell變量取值將轉(zhuǎn)換成整數(shù),與$[]等價(jià):

$ VAR=45 $ echo $(($VAR+3)) $(())中只能用+-*/和()運(yùn)算符,并且只能做整數(shù)運(yùn)算。$[base#n],其中base表示進(jìn)制,n按照base進(jìn)制解釋,后面再有運(yùn)算數(shù),按十進(jìn)制解釋。echo $[2#10+11] echo $[8#10+11] echo $[10#10+11]

轉(zhuǎn)義字符

??和C語(yǔ)言類似,\在Shell中被用作轉(zhuǎn)義字符,用于去除緊跟其后的單個(gè)字符的特殊意義(回車除外),換句話說(shuō),緊跟其后的字符取字面值。例如:

$ echo \\# 在\之后敲回車表示續(xù)行 $ cat \ >a.txt

字符串符號(hào)

??在shell中,字符串既可以用單引號(hào)‘’也可以使用雙引號(hào)“”表示,但它們之間存在一定的差別。

  • 單引號(hào)

    ??單引號(hào)用于保持引號(hào)內(nèi)所有字符的字面值,即使引號(hào)內(nèi)的\和回車也不例外,但是字符串中不能出現(xiàn)單引號(hào)。如果引號(hào)沒(méi)有配對(duì)就輸入回車,Shell會(huì)給出續(xù)行提示符,要求用戶把引號(hào)配上對(duì)。

    # 對(duì)比 $ echo '$PATH' $ echo $PATH
  • 雙引號(hào)

    ??被雙引號(hào)用括住的內(nèi)容,將被視為單一字串。它防止通配符擴(kuò)展,但允許變量擴(kuò)展。作為一種好的Shell編程習(xí)慣,應(yīng)該總是把變量取值放在雙引號(hào)之中。

    # 對(duì)比 $ echo '$PATH' $ echo $PATH $ echo "$PATH"

邏輯運(yùn)算

??Shell提供了!,&&,||語(yǔ)法,和C語(yǔ)言類似,具有Short-circuit特性。注意和!-a -o(在下面條件測(cè)試的內(nèi)容中會(huì)提到)進(jìn)行區(qū)分。

# 如果不是root用戶則輸出提示語(yǔ) $ test "$(whoami)" != 'root' && (echo you are using a non-privileged account; exit 1)# 區(qū)分-a -o # 以下寫(xiě)法等價(jià),注意體會(huì) test "$VAR" -gt 1 -a "$VAR" -lt 3 # 連接兩個(gè)測(cè)試條件 test "$VAR" -gt 1 && test "$VAR" -lt 3 # 連接兩條語(yǔ)句

腳本語(yǔ)法

條件測(cè)試

??條件測(cè)試即測(cè)試一個(gè)條件是否成立,如果測(cè)試結(jié)果為真,則該命令的Exit Status為0,如果測(cè)試結(jié)果為假,則命令的Exit Status為1。

$ var=2 $ test $var -gt 1 $ echo $? 0$ [ $var -gt 3 ] $ echo $? 1

??這里需要強(qiáng)調(diào)的是,左方括號(hào)[是一個(gè)命令的名字,傳給命令的各參數(shù)之間應(yīng)該用空格隔開(kāi),比如,$VAR、-gt、3、]是[命令的四個(gè)參數(shù),它們之間必須用空格隔開(kāi)。命令test或[的參數(shù)形式是相同的,只不過(guò)test命令不需要]參數(shù)。常見(jiàn)測(cè)試命令如下:

[ -d DIR ] 如果DIR存在并且是一個(gè)目錄則為真 [ -f FILE ] 如果FILE存在且是一個(gè)普通文件則為真 [ -z STRING ] 如果STRING的長(zhǎng)度為零則為真 [ -n STRING ] 如果STRING的長(zhǎng)度非零則為真 [ STRING1 = STRING2 ] 如果兩個(gè)字符串相同則為真 [ STRING1 != STRING2 ] 如果字符串不相同則為真 [ ARG1 OP ARG2 ] ARG1和ARG2應(yīng)該是整數(shù)或者取值為整數(shù)的變量,OP是-eq(等于)-ne(不等于)-lt(小于)-le(小于等于)-gt(大于)-ge(大于等于)之中的一個(gè)# 帶與、或、非的測(cè)試命令 [ ! EXPR ] EXPR可以是上表中的任意一種測(cè)試條件,!表示邏輯反 [ EXPR1 -a EXPR2 ] EXPR1和EXPR2可以是上表中的任意一種測(cè)試條件,-a表示邏輯與 [ EXPR1 -o EXPR2 ] EXPR1和EXPR2可以是上表中的任意一種測(cè)試條件,-o表示邏輯或

流程控制

??需要記住的一點(diǎn)是,如果兩條命令寫(xiě)在同一行則需要用;號(hào)隔開(kāi),一行只寫(xiě)一條命令就不需要寫(xiě);號(hào)。

  • if/then/elif/else/fi

    ??if命令的參數(shù)組成一條子命令,如果該子命令的Exit Status為0(表示真),則執(zhí)行then后面的子命令,如果Exit Status非0(表示假),則執(zhí)行elif、else或者fi后面的子命令。if后面的子命令通常是測(cè)試命令,但也可以是其它命令。

    #! /bin/bash echo "Is it morning? Please answer yes or no." read YES_OR_NO if [ "$YES_OR_NO" = "yes" ]; then echo "Good morning!" elif [ "$YES_OR_NO" = "no" ]; then echo "Good afternoon!" else echo "Sorry, $YES_OR_NO not recognized. Enter yes or no." exit 1 fi exit 0# 特殊情況 if :; then echo "always true"; fi # :表示空操作,Exit Status always True
  • case/esac

    ??case命令可類比C語(yǔ)言的switch/case語(yǔ)句,esac表示case語(yǔ)句塊的結(jié)束。C語(yǔ)言的case只能匹配整型或字符型常量表達(dá)式,而Shell腳本的case可以匹配字符串和Wildcard,每個(gè)匹配分支可以有若干條命令,末尾必須以;;結(jié)束,執(zhí)行時(shí)找到第一個(gè)匹配的分支并執(zhí)行相應(yīng)的命令,然后直接跳到esac之后,不需要像C語(yǔ)言一樣用break跳出。

    #! /bin/bash echo "Is it morning? Please answer yes or no." read YES_OR_NO case "$YES_OR_NO" in yes|y|Yes|YES) echo "Good Morning!";; [nN]*) echo "Good Afternoon!";; *) echo "Sorry, $YES_OR_NO not recognized. Enter yes or no." exit 1;; esac exit 0
  • for/do/done

    #! /bin/bash for FILENAME in `ls chap?` do mv $FILENAME $FILENAME~; done
  • while/do/done

    #! /bin/bash COUNTER=1 while [ "$COUNTER" -lt 10 ]; do echo "Here we go again" COUNTER=$(($COUNTER+1)) done
  • break/continue

??break跳出循環(huán),continue跳過(guò)本次循環(huán)步,與C語(yǔ)言不同的是break[n]可以指定跳出幾層循環(huán)。

#! /bin/bash COUNTER=1 while : # 記住:是空命令 doif test $COUNTER -gt 5;thenbreak;fiCOUNTER=$(($COUNTER+1)) done echo $COUNTER;

位置參數(shù)

$0 相當(dāng)于C語(yǔ)言main函數(shù)的argv[0] $1$2... 這些稱為位置參數(shù)(Positional Parameter),相當(dāng)于C語(yǔ)言main函數(shù)的argv[1]、argv[2]... $# 相當(dāng)于C語(yǔ)言main函數(shù)的argc - 1,注意這里的#后面不表示注釋 $@ 表示參數(shù)列表"$1" "$2" ...,例如可以用在for循環(huán)中的in后面。 $* 表示參數(shù)列表"$1" "$2" ...,同上 $? 上一條命令的Exit Status $$ 當(dāng)前進(jìn)程號(hào)

??位置參數(shù)可以用shift命令左移。比如shift 3表示原來(lái)的$4現(xiàn)在變成$1,原來(lái)的$5現(xiàn)在變成$2等等,原來(lái)的$1、$2、$3丟棄,$0不移動(dòng)。不帶參數(shù)的shift命令相當(dāng)于shift 1。

#! /bin/bashecho "The program $0 is now running"echo "The first parameter is $1"echo "The second parameter is $2"echo "The parameter list is $@"shiftecho "The first parameter is $1"echo "The second parameter is $2"echo "The parameter list is $@"

函數(shù)

??和C語(yǔ)言類似,Shell中也有函數(shù)的概念,但是函數(shù)定義中沒(méi)有返回值也沒(méi)有參數(shù)列表。注意函數(shù)體的左花括號(hào)’{‘和后面的命令之間必須有空格或換行,如果將最后一條命令和右花括號(hào)’}'寫(xiě)在同一行,命令末尾必須有;號(hào)。

# 舉個(gè)例子 is_directory() { DIR_NAME=$1 if [ ! -d $DIR_NAME ]; thenreturn 1 elsereturn 0 fi }for DIR in "$@"; do if is_directory "$DIR"then :elseecho "$DIR doesn't exist. Creating it now..."mkdir $DIR > /dev/null 2>&1if [ $? -ne 0 ]; thenecho "Cannot create directory $DIR"exit 1fi fi done

腳本調(diào)試

??執(zhí)行腳本時(shí)可以使用相關(guān)參數(shù)進(jìn)行相應(yīng)的調(diào)試工作:

-n :讀一遍腳本中的命令但不執(zhí)行,用于檢查腳本中的語(yǔ)法錯(cuò)誤

-v :一邊執(zhí)行腳本,一邊將執(zhí)行過(guò)的腳本命令打印到標(biāo)準(zhǔn)錯(cuò)誤輸出

-x :提供跟蹤執(zhí)行信息,將執(zhí)行的每一條命令和結(jié)果依次打印出來(lái)

??具體使用方法包括以下三種:

  • 命令行參數(shù)

    /bin/bash -x ./script.sh
  • shebang提供

    #! /bin/bash -x
  • set命令啟用或禁止調(diào)試

    #! /bin/sh if [ -z "$1" ]; thenset -xecho "ERROR: Insufficient Args."exit 1set +x fi

實(shí)例

開(kāi)機(jī)自動(dòng)腳本

  • 你啟動(dòng)腳本復(fù)制到 /etc/init.d目錄下,假設(shè)腳本文件名為 test.sh
  • 修改權(quán)限,sudo chmod 755 /etc/init.d/test.sh
  • cd /etc/init.d
  • sudo update-rc.d test.sh defaults 95 (95表示啟動(dòng)順序,如需用到網(wǎng)絡(luò)請(qǐng)用較大數(shù)字,如99)

登陸自動(dòng)腳本

  • 修改/etc/motd文件
  • 在/etc/profile.d文件中加入腳本文件

字符串處理

基本操作

${file-$DEFAULT} # 若file沒(méi)有聲明,則使用$DEFAULT作傳回值(空值及非空值時(shí)不作處理) ${file:-$DEFAULT} # 若file沒(méi)有聲明或?yàn)榭罩?#xff0c;則使用$DEFAULT作傳回值(非空值時(shí)不作處理)${file+$DEFAULT} # 若變量已經(jīng)聲明,那么其值是$DEFAULT, 否則是null字符串 ${file:+$DEFAULT} # 若變量已經(jīng)聲明且非空,那么其值是$DEFAULT, 否則是null字符串${file=$DEFAULT} # 如果變量沒(méi)有聲明,則$DEFAULT值賦值給變量 ${file:=$DEFAULT} # 如果變量沒(méi)有聲明,則$DEFAULT值賦值給變量${file?$DEFAULT} # 如果變量沒(méi)有聲明,則$DEFAULT值輸出到STDERR (空值及非空值時(shí)不作處理) ${file:?$DEFAULT} # 如果變量沒(méi)有聲明,則$DEFAULT值輸出到STDERR(非空值時(shí)不作處理)

字符串截取

字符截取
`#`表示去掉左邊的字符(單一匹配) `%`表示去掉右邊的字符(單一匹配) `##`表示去掉左邊的字符(貪婪匹配) `%%`表示去掉右邊的字符(貪婪匹配)${file#*/} # home/jeffery/readme.txt ${file##*/}:# readme.txt ${file#*.}:# md.txt ${file##*.}:# txt ${file%/*}# /home/jeffery ${file%%/*}# '' ${file%.*}# /home/jeffery/readme.md ${file%%.*}# /home/jeffery/readme
子串截取
# 字符串位置從0開(kāi)始計(jì)數(shù)${#file} # 獲取字符串的長(zhǎng)度 ${file:0:5} # 從第0個(gè)字符起截取5個(gè)字符,/home ${file:5:5} # 從第5個(gè)字符起截取5個(gè)字符,/jeff# 以下兩個(gè)表示截取最后四個(gè)字符 ${file: -4} ${file:(-4)}

字符串替換

${file/str1/str2} # 將字符串file中的第一個(gè)str1替換為str2 ${file//dir/path} # 將字符串file中的str1替換為str2

大小寫(xiě)轉(zhuǎn)換

echo "$file" echo ${file^} echo ${file^^} echo ${file,} echo ${file,,} echo ${file~} echo ${file~~}# ^大寫(xiě),,小寫(xiě), ~大小寫(xiě)切換, 重復(fù)一次只修改首字母,重復(fù)兩次則應(yīng)用于所有字母

數(shù)組

普通數(shù)組

my_array=(A B "C" D) # 定義數(shù)組 declare -a my_array2 # 定義數(shù)組方法2 my_array2[0]=Becho ${my_array[0]} # 獲取數(shù)組元素 echo ${my_array[*]} # 獲取所有元素 echo ${my_array[@]} # 獲取所有元素echo ${#my_array[*]} # 獲取數(shù)組長(zhǎng)度 echo ${#my_array[@]} # 獲取數(shù)組長(zhǎng)度unset my_array[0] # 刪除第一個(gè)元素echo ${my_array[@]:0:2} # 切片操作,從0開(kāi)始取值,取兩個(gè)for v in ${my_array[@]}; do # 數(shù)組遍歷echo $v; donemy_array+=(a b c) # 往數(shù)組中添加元素

關(guān)聯(lián)數(shù)組

??關(guān)聯(lián)數(shù)組類似于python,C#等語(yǔ)言中的DICTIONARY類型

declare -A dict # 定義關(guān)聯(lián)數(shù)組dict=([c]=3 [d]=4) # 賦值dict+=([a]=1 [b]=2) # 向關(guān)聯(lián)數(shù)組添加鍵值對(duì)echo ${!dict[@]} # 獲取所有索引echo ${dict[a]} # 通過(guò)key獲取value

注意事項(xiàng)

??注意區(qū)分以下符號(hào)的使用,具體可見(jiàn)上文:

  • 引用變量-----> $DATE 或 ${DATE}
  • 命令代換----> `date` 或 $(date)
  • 算術(shù)代換---->$(()) 或 $[]
  • 邏輯運(yùn)算符 !-a -o 和 !&& ||
  • 條件測(cè)試 [] 和 [[]]
    ?? 如果a為空,那么[$a -eq 0]會(huì)報(bào)錯(cuò),但是[[$a -eq 0]]不會(huì),所以一般都會(huì)使用[[]]或者是["$a" -eq 0]。

總結(jié)

以上是生活随笔為你收集整理的Shell脚本编程详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。