【Linux 命令行與 shell 腳本編程大全】 13 更多的結(jié)構(gòu)化命令(for/while)

導(dǎo)覽

  1. 在 shell 腳本中也可以使用 for 、 while 循環(huán)
  2. until 循環(huán)則是和 while 循環(huán)在條件判斷規(guī)則上完全相反的的一種循環(huán)操作
  3. break 命令支持直接終止循環(huán),同時(shí)還可以通過(guò) break n 指定要終止的循環(huán)層級(jí)
  4. contiune 命令支持直接中止當(dāng)前循環(huán),直接進(jìn)入下次循環(huán),同時(shí)還可以通過(guò) continue n 指定要中止的循環(huán)層級(jí)
  5. 在循環(huán)結(jié)束后可以再最后使用管道干預(yù)腳本的輸出結(jié)果,可以使用重定向?qū)⒛_本的輸出導(dǎo)入文件

13.1 for 命令

  1. 在 shell 中可以使用 for 命令來(lái)循環(huán)遍歷一系列值,基本語(yǔ)法如下:
    • 使用效果和其他語(yǔ)法的 for 循環(huán)基本一致
for var in list
do
  commands
done

13.1.1 讀取列表的值

  1. for 循環(huán)最基本的用法就是讀取列表的值,如下圖
    • name 是在 for 循環(huán)中聲明的局部變量,但是在循環(huán)結(jié)束后,該變量依舊可以正常被訪問(wèn),或者被修改
[ttxie@41 part13]$ cat for-list.sh 
#!/bin/bash

for name in ffjff fffoksfl kkkk lllll
do
   echo "當(dāng)前的名字是${name}"
done

echo "最后名字是: ${name}"

name="newnames"

echo "當(dāng)前名字是: ${name}"
image.png

13.1.2 讀取列表中的復(fù)雜值

  1. 如果需要被遍歷的列表中的值存在一些復(fù)雜的組合,例如:?jiǎn)我?hào)、雙引號(hào)、空格
  2. 這個(gè)時(shí)候就需要先對(duì)這些特殊符號(hào)進(jìn)行轉(zhuǎn)義,方式有以下兩種
    • 使用反斜線將單引號(hào)轉(zhuǎn)義
    • 使用雙引號(hào)將用到單引號(hào)、空格的值進(jìn)行包裹
  3. 寫一個(gè)簡(jiǎn)單的例子演示一下,如下圖
    • 需要注意的是,在第一個(gè)循環(huán)中的列表,連續(xù)使用了兩個(gè)沒(méi)有被轉(zhuǎn)義的單引號(hào),得到了如下的輸出結(jié)果,如果這里只使用了一個(gè)單引號(hào),例如 macbook's cpu is ,造成的錯(cuò)誤將會(huì)更嚴(yán)重過(guò),會(huì)影響整個(gè) shell 腳本無(wú)法正常輸出結(jié)果

      image

13.1.3 從變量讀取列表

  1. 將需要被循環(huán)的列表存儲(chǔ)到變量中,再通過(guò) for 循環(huán)進(jìn)行遍歷輸出,會(huì)更美觀,如下圖
    • 變量不僅可以接受待輸出的列表值,還能對(duì)列表值進(jìn)行拼接
    • 不過(guò)這種表現(xiàn)形式在其他語(yǔ)言中更像是字符串而已,不用介意,這就是 shell 的方式
[ttxie@41 part13]$ cat for-variable.sh 
#!/bin/bash

names="asssss 1gkmgk 2jkmk"
names=$names" rys"     ##追加字符串

for name in $names
do
echo "name: ${name}"
done
image.png

13.1.4 從命令讀取值

  1. 可以用命令替換來(lái)執(zhí)行任何可能產(chǎn)生輸出的命令,然后在 for 循環(huán)的 in 關(guān)鍵字后使用該命令的輸出,如下圖
    • 變量 directory 存儲(chǔ)了一個(gè)目錄,然后再 for 循環(huán)中使用 $(ls $directory) 輸出這個(gè)目錄的內(nèi)容
[ttxie@41 part13]$ cat for-command.sh
#!/bin/bash

for file in `ls $PWD`
do
  echo "當(dāng)前目錄有的文件是: ${file}"
done

#-----------還可以這樣寫-----------

for file in $(ls $PWD)
do
  echo "當(dāng)前目錄有的文件是: ${file}"
done

#------------遍歷文件中的字符-----------
for state in `cat for-variable.sh`
do
  echo ${state}
done

image.png

13.1.5 更改字段分隔符

  1. for 循環(huán)之所以能將字符串的空格作為列表元素的分隔符,是因?yàn)橄到y(tǒng)中存在 內(nèi)部字段分隔符( Internal Field Separator ,IFS ) 的全局環(huán)境變量

  2. IFS 環(huán)境變量定義了 shell 作為字段分隔符的多個(gè)具體字符,默認(rèn)情況下,有以下幾種

    • 空格 IFS=$'\ '
    • 制表符 IFS=$'\t'
    • 換行符 IFS=$'\n'
  3. IFS 環(huán)境變量可以在 shell 腳本中進(jìn)行臨時(shí)修改,如下圖

    • 下面這個(gè)例子中,將 IFS 的值改為只能識(shí)別換行符,所以就能順利的通過(guò)循環(huán)把每行的內(nèi)容輸出
[ttxie@41 part13]$ cat for-IFS.sh
#!/bin/bash

IFS=$'\n'

for line in $(cat $PWD/for-variable.sh)
do
 echo ${line}
done
image.png
  1. 如果想要為 IFS 指定多個(gè)值,可以直接使用 IFS=$'\n':;" 即可

    • 這就表示換行符、冒號(hào)、分號(hào)、雙引號(hào)都會(huì)被識(shí)別為字段分隔符
  2. 修改的IFS的值,只在腳本內(nèi)適用,不改變?nèi)肿兞俊?br> 有時(shí)候在一個(gè)大腳本中,有的地方需要修改IFS的值,然后忽略這次的修改,在腳本的其他地方繼續(xù)沿用IFS默認(rèn)值,可以這樣寫:


    image.png

13.1.6 用通配符讀取目錄

  1. 在使用 for 循環(huán)時(shí),就算不通過(guò) ls 命令( 在 13.1.4 中有演示 )也能讀取目錄的內(nèi)容,使用 文件擴(kuò)展匹配 即可,如下圖
    • 其實(shí)就是在路徑最后使用通配符
[ttxie@41 part13]$ cat for-wildcards.sh
#!/bin/bash

dir="/BI/xtt/toolkits/shell/part13/*"

for file in ${dir}
do
 if [ -d "$file" ]
 then
   echo "$file is a dir"
 elif [ -f "$file" ]
 then
   echo "$file is a file"
 fi
done
image.png

"$file" 加引號(hào) 是為了規(guī)避含有空格的文件名

  1. for 循環(huán)中還可以同時(shí)指定多個(gè)目錄,實(shí)現(xiàn)對(duì)輸出結(jié)果進(jìn)行拼接的效果,如下圖
    • 由于輸出的內(nèi)容太多,最后執(zhí)行的時(shí)候通過(guò) | head 命令只顯示了頭部的幾條信息
[ttxie@41 part13]$ cat for-wildcards_plus.sh
#!/bin/bash

dir1="/BI/xtt/toolkits/shell/part13/*"
dir2="/BI/xtt/toolkits/shell/part12/*"

for file in ${dir1} ${dir2}
do
  if [ -d "$file" ]
  then
    echo "$file is a dir"
  elif [ -f "$file" ]
  then
    echo "$file is a file"
  fi
done
image.png

13.2 C 語(yǔ)言風(fēng)格的 for 命令

13.2.1 C 語(yǔ)言的 for 命令

  1. 在 shell 中可以使用和 C 語(yǔ)言風(fēng)格類似的 for 命令,基本語(yǔ)法如下
for (( variable assigment ; condition ; iteration process ))
do
  commands
done

for (( a = 1 ; a < 10 ; a++ ))
do
  echo "a : $a"
done

  1. 上述的 for 命令語(yǔ)法在以下幾個(gè)方面沒(méi)有遵循 shell 標(biāo)準(zhǔn)
    • 變量賦值可以有空格
    • 在條件中調(diào)用變量時(shí),不需要通過(guò)美元符號(hào)開(kāi)頭
    • 迭代過(guò)程的算式不需要使用 expr 命令
  2. 寫一個(gè)簡(jiǎn)單的例子演示一下,如下圖
[ttxie@41 part13]$ cat for-normal.sh
#!/bin/bash

for (( i=1; i<=10; i++ ))
do
  echo $i
done
image.png

13.2.2 使用多個(gè)變量

  1. 在這種風(fēng)格的 for 循環(huán)中,可以在條件中定義多個(gè)變量,如下圖
    • 可以看到,在變量定義時(shí),同時(shí)指定了變量 a 和 b ,并在最后規(guī)定了 a 和 b 的迭代方式
    • 但需要注意的是,就算可以定義多個(gè)變量,但循環(huán)結(jié)束的條件只能有一個(gè)
[ttxie@41 part13]$ cat for-normal-plus.sh
#!/bin/bash

for (( a=1, b=10; a<=10; a++, b-- ))
do
  echo "$a - $b"
done
image.png

13.3 while 命令

13.3.1 while 的基本格式

  1. 當(dāng) condition 返回非零的退出狀態(tài)碼時(shí),循環(huán)就會(huì)結(jié)束,否則循環(huán)將一直進(jìn)行
while [ condition ]
do
  commands
done

  1. 寫一個(gè)簡(jiǎn)單的例子演示一下,如下圖
    • 變量 num 初始值為 1
    • 循環(huán)結(jié)束的條件是 num 小于 10
    • 符合循環(huán)條件時(shí),num 每次都會(huì)在輸出后,累加 1 ,累加的方式是在第 12 章中學(xué)到的使用雙括號(hào)賦值
    • 最后當(dāng) num 輸出到 9 時(shí),累加后等于 10 ,則無(wú)法再次循環(huán)
[ttxie@41 part13]$ cat while.sh 
#!/bin/bash

n=1

while [ $n -lt 10 ]
do
  echo "n的值:${n}"
  (( n = ${n} + 1 ))
done
image.png

13.3.2 使用多個(gè)測(cè)試命令

  1. while 命令可以在條件語(yǔ)句中定義多個(gè) test 命令,但只有最后一個(gè)命令會(huì)被作為 檢測(cè)循環(huán)是否結(jié)束 的條件,如下圖
    • 可以看到,在條件中定義了兩個(gè)測(cè)試命令,需要注意的是,每個(gè)測(cè)試命令都必須獨(dú)占一行

    • 其他內(nèi)容都和上一個(gè) shell 腳本沒(méi)有區(qū)別,但是在輸出時(shí),最后會(huì)多輸出一個(gè) 10 ,這也就是 while 命令支持多個(gè)測(cè)試命令的意義所在了

      image

13.4 until 命令

  1. until 命令的效果和 while 命令正好相反,但兩者的基本語(yǔ)法一致
    • while 命令是當(dāng)條件返回非零時(shí),就結(jié)束
    • until 命令則是當(dāng)條件返回零時(shí),就結(jié)束
  2. 寫一個(gè)簡(jiǎn)單的例子演示一下,如下圖
    • 可以看到,當(dāng) until 命令使用了和之前 while 命令一致的條件判斷時(shí),循環(huán)體根本無(wú)法進(jìn)入

    • 但當(dāng)使用了之前 while 命令相反的條件判斷時(shí),循環(huán)體就順利進(jìn)入了

      image

13.5 嵌套循環(huán)

  1. 嵌套循環(huán)( Nested Loop ) 其實(shí)就是多個(gè) for 、while 、until 命令嵌套在一起

    • 被嵌套的叫 內(nèi)部循環(huán)( Inner Loop )
  2. 寫一個(gè)簡(jiǎn)單的例子演示一下,如下圖

    image

13.6 循環(huán)處理文件數(shù)據(jù)

  1. 這個(gè)內(nèi)容其實(shí)在上文中的 13.1.5 更改字段分隔符 小節(jié)中就有演示
  2. 這里寫一個(gè)稍微復(fù)雜一點(diǎn)的升級(jí)版演示一下,如下圖
    • 在讀取文件之前,將 IFS 的值改為了只識(shí)別換行符

    • 在循環(huán)中輸出每行的內(nèi)容后,又將 IFS 的值改為只識(shí)別空格

    • 這個(gè)時(shí)候?qū)⒚啃械臄?shù)據(jù)再次循環(huán),就可以得到每行的具體字符

      image

13.7 控制循環(huán)

13.7.1 break 命令

  1. 在循環(huán)中使用 break 命令可以直接退出循環(huán),在 for 、while 、 until 中都可以使用

13.7.1.1 退出單個(gè)循環(huán)

  1. 可以看到,按照正常的循環(huán)邏輯,循環(huán)體應(yīng)該可以執(zhí)行 10 次,但是由于添加了當(dāng)值等于 5 時(shí)就執(zhí)行 break 命令的條件判斷,所以在值等于 5 時(shí),循環(huán)就停止了
[ttxie@41 part13]$ cat for-break.sh
#!/bin/bash

for (( n=1; n<=10; n++ ))
do
  echo "n的值為:$n"

  if [ $n -eq 5 ]
  then
    break
  fi

done
image.png

13.7.1.2 退出內(nèi)部循環(huán)

  1. 可以看到,本來(lái)外部循環(huán)可以執(zhí)行 5 次,并且在值小于 3 時(shí),每次外部循環(huán)執(zhí)行時(shí),內(nèi)部循環(huán)都可以執(zhí)行

  2. 但在第一次外部循環(huán)中,內(nèi)部循環(huán)執(zhí)行兩次后,就由于條件判斷被中斷了

    image

13.7.1.3 從內(nèi)部循環(huán)直接退出外部循環(huán)

  1. break 命令支持使用 break n 指定循環(huán)的層級(jí),表示會(huì)直接退出 n 層的循環(huán)體,如下圖
    • 可以看到,shell 腳本的內(nèi)容和上一個(gè)例子基本一致,唯一的修改就是內(nèi)不循環(huán)的 break 改成了 break 2

    • 在執(zhí)行腳本后,之前內(nèi)部循環(huán)觸發(fā) break 后,這次造成的結(jié)果是整個(gè) shell 腳本的終止

      image

13.7.2 continue 命令

  1. 在循環(huán)中使用 continue 命令可以直接中止當(dāng)前循環(huán),直接進(jìn)入下一次循環(huán),在 forwhile 、 until 中都可以使用

  2. 但是在 whileuntil 中使用 continue 時(shí)需要注意,不能把 continue 放在迭代條件之前,否則就會(huì)造成無(wú)限循環(huán),如下圖

    • 原本 while 循環(huán)的條件判斷是當(dāng) num 小于 5 時(shí),就一直循環(huán),每次循環(huán) num 都會(huì)加 1 ,所以一共會(huì)循環(huán) 5 次

    • 但是在 num 的累加操作 (( num = $num + 1 )) 之前增加了一個(gè)當(dāng) num = 2 時(shí)就 continue 的操作

    • 這就導(dǎo)致當(dāng) num 等于 2 時(shí),當(dāng)前循環(huán)就會(huì)被中止,直接進(jìn)入下一次循環(huán),而 num 的累加操作每次都沒(méi)有被執(zhí)行

    • 最后就無(wú)限循環(huán)了

      image
  3. continuebreak 一樣,也可以通過(guò)指定層級(jí)來(lái)跳過(guò)對(duì)應(yīng)的層級(jí)的循環(huán),如下圖

    • 本來(lái)外部循環(huán)會(huì)循環(huán) 5 次,并且每次外部循環(huán)時(shí),內(nèi)部循環(huán)都會(huì)循環(huán) 5 次

    • 但是由于 continue 2 的加入,當(dāng)內(nèi)部循環(huán)的值等于 2 時(shí),外部循環(huán)也會(huì)被跳過(guò)

      image

13.8 處理循環(huán)的輸出

  1. 在循環(huán)的 done 關(guān)鍵字之后可以使用管道或者重定向操作
  2. 結(jié)合管道的操作在 13.7.2 continue 命令 中已經(jīng)有演示,效果就是可以對(duì)腳本的輸出進(jìn)行干預(yù)
    • 不過(guò)這個(gè)演示中是將管道放在了腳本執(zhí)行時(shí)
    • 也可以將管道放在腳本內(nèi)部,done 關(guān)鍵字之后
  3. 結(jié)合重定向的操作則是可以將腳本的輸出重定向到文件中,如下圖
    • 在循環(huán)結(jié)束后通過(guò) > result 將輸出結(jié)果重定向到 result 文件中

    • 可以看到,腳本執(zhí)行后終端沒(méi)有輸出任何語(yǔ)句

    • 查看當(dāng)前目錄可以看到出現(xiàn)了一個(gè) result 的文件,里面的內(nèi)容就是剛才執(zhí)行腳本的輸出內(nèi)容

      image

13.9 實(shí)例

13.9.1 查找可執(zhí)行的文件

掃描PATH環(huán)境變量中可執(zhí)行的文件:

[ttxie@41 part13]$ cat find-read.sh
#!/bin/bash

IFS=:

for folder in $PATH
do
  echo "folder: $folder"
  for file in $folder/*
  do  
    if [ -x $file ]
    then
      echo "    $file"
    fi  
  done
done
image.png

部分內(nèi)容轉(zhuǎn)載來(lái)自:
作者:asing1elife
鏈接:http://www.itdecent.cn/p/b1522b99711a
來(lái)源:簡(jiǎn)書(shū)
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容