Overview of Content
這篇文章將引導您深入了解 Bash 腳本中的迴圈和循環控制技巧
從簡單的 for-in
命令到 while
和 until
語句,我們將一步步地探索如何利用這些工具來處理列表數據、讀取變數、以及執行命令。此外,我們還會深入研究如何使用 IFS
字串分隔符和通配符來擴展您的腳本功能。無論您是初學者還是有一定經驗的用戶,這篇文章都將為您打開 Bash 腳本的新世界
寫文章分享不易,如有引用參考請詳註出處,如有指導、意見歡迎留言(如果覺得寫得好也請給我一些支持),感謝 😀
個人程式分享時比較注重「縮排」,所以可能不適合手機的排版閱讀,建議切換至「電腦版」、「平板版」視窗看 😀
for-in 命令
bash 提供 for 命令,其格式如下:
for var in list
do
commands
done
● 也可以把全部寫在同一句 command 中(使用
;
隔開每個指令)
for <var> in <list> ; do ; <commands> ; done
讀取列表數據
● 如果有使用過其他語言(C、Java... 等等),其實 Shell 的 for 回圈其實差不多意思,它會在循環的過程中刷新暫存值
#!/bin/bash
# 暫存值 tmp
for tmp in A B C D E F G ; do
echo "I get the word of $tmp"
done
● 並且列表是使用 空格 來區分每個數據,如果數據中有空格,可以使用以下兩個方案解決
A. 跳脫字元 \
:
#!/bin/bash
for word in Hello, I\'m Kyle, we\'re firend. ; do
echo "word: $word"
done
B. 雙引號:
#!/bin/bash
for test in "Hello world" "Check out" "Yo yo 123" ; do
echo "$test"
done
讀取數據變數
● 從變數中讀取列表需要注意:1. 使用 $
符號引用變量、2. 仍使用空格來區分每個數據
#!/bin/bash
var_list="My meet at 8.30am."
# 記得使用 `$` 引用
for tmp in $var_list ; do
echo "var word: $tmp"
done
讀取命令數據
● 可以用 命令替換( 格式:$( command )
)來執行任何能輸出列表的命令,再放置到 for 原本 list 的位置
以下使用 cat 命令輸出指令
A. 先產生一個文件,之後會使用 cat
命令讀取該文件
Hello
World
ABC
Shopping mall
"Yo yo man"
I\'m Kyle
B. 使用 命令替換 來執行會輸出列表的命令
#!/bin/bash
# 目前該檔案在相同路徑之下,如果不在同路徑之下,需使用完全路徑
file_name="fakeFileList"
for item in $( cat $file_name ) ; do
echo "Visit file by for, word: $item"
done
執行 Shell 的結果如下
● 透過結果可以看出輸出列表會以
空格
、換行
來區分每個字串● 另外可以看出使用跳脫字元
\
、“”
並不會讓字串當成一個句子完整輸出這跟 字串分隔符 有關,可以透過它來解決這個問題
拓展細節:IFS 字串分隔符
● IFS 内部字段分隔符 (internal field separator
) 是用來標明,如何去分隔字符為一個字串;bash shell 默認 IFS 如下
● 空格
● 制表符(\t
)
● 換行(\n
)
● 替換 IFS 的方式如下
IFS=<分隔符號*>
範例:
IFS=$'\n':;"
代表的含義就是就是使用\n
、:
、;
、"
作為字段分隔符
換行符號一般來說就是一個符號,如果超過一個符號就必須使用
$""
、$''
來包裹多符號
● 替換 IFS 為 \n
#!/bin/bash
# \n 就是超過兩個符號,所以必須使用 $'' 包裹
IFS=$'\n'
file_name="fakeFileList"
for item in $( cat $file_name ) ; do
echo "Visit file by for, word: $item"
done
分隔符
IFS=$'\n'
● 替換 IFS 為 :
符號 來讀取 /etc/passwd
檔案
#!/bin/bash
IFS_OLD=$IFS
IFS=:
for item in $( cat /etc/passwd | grep alien ) ; do
echo "Visit file by for, word: $item"
done
分隔符
IFS=:
通配符:讀取目錄
● list 列表可以使用「通配符」加部份文件名,來讀取文件目錄
#!/bin/bash
# 讀取 /etc/s 開頭的所有文件
for file in /etc/s* ; do
if [ -d "$file" ] ; then
echo "$file is directory."
elif [ -f "$file" ] ; then
echo "$file is file."
else
echo "Strang $file"
fi
done
C 語言風格的 for
Bash shell 也可以使用類似 C 語言風格的迴圈,其格式如下
for (( variable assignment ; condition ; iteration process ))
do
commands
done
● 注意,C 語言迴圈與 bash shell 差異:
● 變量赋值可以有空格(Shell 變量)
● 條件變量不用
$
引用● 迭代過程的數學運算不用特別處理(不用使用 expr、或特殊符號)
如同 if 迴圈的高級特性
(( expression ))
C 語言的迴圈腳本
● Bash shell 檔案中使用 C 語言風格的迴圈
#!/bin/bash
for (( i = 1; i <= 10; i++)) ; do
echo "Number is $i"
done
● 既然是 C 語言的迴圈,就可以使用多個條件變量,變量之間使用逗號 ,
區分
#!/bin/bash
# 多條件變量
for (( i = 1, j = 10; i <= 10; i++, j--)) ; do
echo "The number of i is $i, and j is $j"
done
while 語句
while 語句的命令會判斷 test command
的退出碼,如果是 0(代表的就是「判斷成立」)就會無限一直執行迴圈內容,其格式如下:
while test command
do
other commands
done
# 或是使用 [] 替代 test -------------------------------------
while [ command ]
do
other commands
done
● 想想,其實如果要達成「判斷成立」的特性,其實並非只有使用 test 語句可以達成,也可以使用其他的判斷、特性去達成!
while ls | grep -q pdf; do echo -n "There is afile with pdf, $(pwd)" done
while:基礎使用
● while 每次都會檢查 test 命令的退出碼,以下是基本用法
#!/bin/bash
var=10
# 使用 test 命令判斷 gather than 0 (大於 0)
while [ $var -gt 0 ] ; do
# 修改變量條件
echo "variable: $(( var-- ))"
done
記得在 while 迴圈內修改變量條件,否則容易造成死迴圈
while:多條件判斷
● while 中可以有多條件,不同條件只需要換行即可
#/bin/bash
var=10
# 多條件 while 判斷
while echo $var
[ $var -ge 0 ] ; do
echo "variable: $(( --var ))"
done
while 迴圈的結束條件是,所有判斷的退出碼都為 0 才會退出
while 配合管道 pipe
● while 的測試命令(test
)可以配合 pipe(管道) |
使用是滿常見的操作,這裡只要注意 test 測試命令的判斷是取管道的最後返回值做判斷
範例如下
#/bin/bash
FILE=/tmp/whileTtest.$$
echo firstline > $FILE
# 將 `tail -10 $FILE` 的結果丟至 `grep -q firstline` 中
# 也就是仍是一個 test 判斷
# 判斷重點在 `grep -q firstline`
while tail -10 $FILE | grep -q firstline; do #
# 對螢幕輸出資訊
echo -n Number of lines in $FILE:' '
wc -l $FILE | awk '{print $1}'
# 追加輸出
echo newline >> $FILE
cat -n $FILE
done
rm -f $FILE
until 語句
until 語句的判斷與 while 相反,until 判斷 test 語句退出碼不為 0 就一直執行迴圈;其格式如下
until test commands
do
other commands
done
# 使用 [] 替代 test -------------------------------------
until [ commands ]
do
other commands
done
until 使用
● until 的使用同 while 差異不大,只是要記得 until 是判斷退出值為 0 才結束迴圈
#!/bin/bash
var=10
until test $var = 0 ; do
echo "variable: $(( var-- ))"
done
until 也可以執行多條件判斷,這邊就不示範了
循環控制
上面所有的循環語句(for、while、until)都可以透過以下兩個命令來控制循環內部的情況
● break 命令
● continue 命令
循環中斷:break
● break 命令可以用在循環中,其格式如下(可以執定跳出的層數,沒有指定預設則為 1)
break [跳出層數=1]
A. 跳出單個循環
#!/bin/bash
for (( a = 10; a > 0; a-- )) ; do
if [ $a -ne 4 ] ; then
echo "current number: $a"
else
echo "break for at :$a"
break
fi
done
B. 跳出指定循環
#!/bin/bash
for (( a = 10; a > 0; a-- )) ; do
echo "Inner for : $a"
var=30
while [ $var -gt 5 ] ; do
echo "Inner while: $(( var -= 5 ))"
if [ $var -eq 5 ] ; then
echo "break from inner cricle. $var"
break 2
fi
done
done
循環跳過:continue
● continue 命令可以中斷當前執行的迴圈,但 並不會跳出,而時執行下一次迴圈,其格式如下(可以執定跳過的層數,沒有指定預設則為 1)
continue [跳過層數=1]
A. 跳過單個循環
#!/bin/bash
var=5
until [ $var -eq 0 ] ; do
var=$[ $var - 1 ]
if [ $var -eq 3 ] ; then
# 跳過 var == 3 的數值,再次進入 until 迴圈
continue
fi
echo "variable: $var"
done
B. 跳過指定循環
#!/bin/bash
var=5
until [ $var -eq 0 ] ; do
var=$[ $var - 1 ]
echo "variable until: $var"
for (( a = 0; a < 5; a++ )) ; do
echo "vairable for: $a"
if [ $a -eq 2 ] ; then
## 跳到外部的 until 回圈
continue 2
fi
done
done
循環結果的輸出:done >
透過重新定向,可以將回圈的輸出的內容導向到某個文件(這時螢幕就不會輸出任何數據);其格式如下
while [ command ]
do
other command
done > file
迴圈重新導向範例:
#!/bin/bash
for tmp in A B C D E F G ; do
echo "I get the word of $tmp"
# 輸出重新導向文件
done > "The command for command finish."
更多 Linux Shell 知識
Linux 環境、服務:用戶、權限管理
● Linux 環境、服務、管理:
在這個主題中,你可以探索各種 Linux 環境、服務和管理相關的重要概念…
● 了解 Linux 組成:內核責任、GNU 工具、桌面環境 | 基礎版到發行版
在這裡,你將了解 Linux 系統的基本組成部分,包括內核、GNU 工具和桌面環境,並了解不同 Linux 發行版之間的差異
● 探索 X Window 服務與桌面環境:Linux 視窗 XWindow 服務、D-Bus 機制
這裡探討了 Linux 系統中 X Window 服務和 D-Bus 機制的工作原理,讓你深入了解桌面環境的背後運作方式
● Linux 系統管理入門:安全性、用戶管理與權限設定指南
在這個指南中,你將學習如何管理 Linux 系統,包括安全性、用戶管理和權限設定,以確保系統的安全和有效運作
● 認識身份驗證與權限管理:UNIX UID、使用者驗證與 PAM | PAM 設定
這裡介紹了 UNIX 系統中的身份驗證機制和權限管理方式,包括 UNIX UID、使用者驗證和 PAM(
Pluggable Authentication Modules
)設定
Linux Shell 相關知識
● Linux Shell 相關知識:
這個主題涵蓋了各種與 Linux Shell 相關的知識,從基礎到進階都有…
● Shell 基礎知識:包括 Shell 的基礎使用以及差異,還有變數以及計算
● 認識命令行:Shell 類型、命令差異 | Sub Shell 關係 | Builtin 命令
這裡介紹了命令行中不同類型的 Shell,以及各種 Shell 命令之間的區別和內建命令的用法
● Shell 全局及區域變數、特殊變數及環境變數 | Shell 啟動順序 | Array 變數
學習如何在 Shell 中使用全局變數、特殊變數和環境變數,以及如何設置和管理這些變數
● 探索腳本與命令:Shell 腳本的必備相關知識 | 腳本的數學運算
這裡介紹了 Shell 腳本的基本知識和常用技巧,包括如何執行腳本和進行數學運算
● Shell 結構化
● Shell 腳本程式中的條件語句和高級特性 | Shell 結構化 & 判斷
該篇文章是介紹結構化腳本的基礎以及特殊的高級技巧,轉著於腳本中的邏輯判斷
● 掌握 Bash 腳本中的迴圈與循環控制技巧 | Shell 結構化 & 循環
接著是腳本中的循環與控制的技巧,它可以讓我們在 Shell 腳本中有更多的判斷與技巧
● 探索 Shell 函數與腳本庫 | Shell 結構化 & 函數
這裡你將會學在到結構化腳本的重要技巧「函數」,它可以讓你建立可重複利用的腳本,以節省我們之後開發的時間
● Shell 掌握參數處理與用戶輸入技巧 | Shell 結構化 &輸入互動
不可互動的腳本有時候相對無趣,這篇文章有分享如何讓腳本與使用者產生交互互動,並依照使用者輸入的參數做讀取
● Shell script 進階
● Shell 命令輸入與輸出指南:掌握標準文件描述符與重定向 | 臨時文件
掌控 Shell、指令的輸出輸入是成為進階使用 CLI 之人必經的一課,透過這篇文章可以了解到輸出輸入、臨時文件等等資訊
● 探索 Linux 訊號與後台進程管理:安排定期啟動腳本 | 運行時啟動腳本
信號可以算是 Shell 腳本與 Linux 系統之間的通訊方式,透過這個文章,我們可以了解到信號與 Shell 腳本的安排時間
Linux 硬體規劃:檔案系統、分區
● Linux 硬體規劃:檔案系統、分區:
最後,這個主題涵蓋了 Linux 系統中硬體結構相關的重要概念…
● Shell 文件和目錄操作的常用命令和技巧 | 尋找檔案
這裡介紹了 Shell 中常用的文件和目錄操作命令,包括如何尋找文件和管理文件系統
● 深入探索 Linux 文件系統與硬體管理 | 分區、檔案系統、邏輯卷 | inode
學習如何管理 Linux 文件系統,包括分區、文件系統和邏輯卷等相關概念,以及文件系統中的 inode 機制
● 理解 Unix/Linux 設備偵測、建立 | 認識與使用 udevd | SCSI 與 Linux 核心
這裡介紹了 Unix/Linux 系統中的設備偵測和管理,包括如何使用 udevd 和 SCSI 相關的 Linux 核心知識