在日常的 Linux 運維與腳本編寫中,我們經常需要依次執行多條命令。本篇將帶你徹底搞懂三種命令順序執行方式:;
、&&
和 ||
,并通過實用示例掌握它們的區別與應用場景。
一、為什么要了解多命令執行方式?
在實際運維或腳本編寫中,往往需要連續執行多條命令:
- 有時希望某條命令出錯也能繼續往下做;
- 有時希望后續命令僅在前面執行成功后才運行;
- 也有時要在某條命令失敗時額外做補救。
掌握 ;
、&&
、||
這三種操作符,就能靈活控制“先后順序”與“成功/失敗依賴”,讓腳本更健壯、更易維護。
二、;
— 命令分隔符也叫順序執行符
表示:兩個命令是獨立的,無論前一個命令執行結果如何,后一個都會執行
1. 語法格式
命令1 ; 命令2 ; 命令3 ; …
解釋:使用分號(;
)將多條命令分隔,Shell 會依次執行它們,無論前一條命令是否成功,都會繼續執行下一條。
2. 示例
- 命令1,whoami 查看當前用戶
- 命令2,cat file.txt 查看當前目錄file.txt文件(這里file.txt不存在,執行時會報錯,也就是第二條命令執行失敗)
- 命令3,ls -la 查看當前目錄的所有文件/目錄
#!/bin/bash
whoami;cat file.txt;ls -la
3. 輸出結果
即使第二條寫成了 cet file.txt
(寫錯命令),也不會阻止第三條執行(下面我把 cat
改為 cet
)
#!/bin/bash
whoami;cet file.txt;ls -la
4. 詳細說明
- 執行順序:從左到右逐條執行。
- 錯誤忽略:前一條返回非 0 (失敗)也不影響下一條的執行。
- 適用場景:當你只需保證“一行里列出的命令都會嘗試執行一次”,不在乎它有沒有出錯。例如:批量創建目錄后,按順序設置權限、啟動服務等,即使中間某步出錯,也要繼續嘗試后面操作。
5. 小結
- 作用:無條件順序執行,多條命令都會執行。
- 適合場景:不關心某步是否成功,只要“都試一遍”即可。
- windows CMD中,
;
對應 Windows 的&
其他兩個都一樣
三、&&
—— 邏輯與運算符
表示:如果前面的命令執行成功,再執行后面的命令
1. 語法格式
命令1 && 命令2 && 命令3 && …
解釋:只有當 命令1
返回值為 0(成功)時,才會執行 命令2
;同理,命令2
成功后才執行 命令3
。一旦某條命令失敗(非 0),后續命令將不再執行。
2. 示例
當前目錄下不存在test
目錄,所以執行 cd test
時會提示錯誤
#!/bin/bash
echo "執行第一條命令" && cd test && "執行第三條命令"
cd test && echo "執行第二條命令" && "執行第三條命令"
3. 輸出示例
4. 詳細說明
- 成功觸發:
&&
鏈中的一項只有在前一項成功時才執行。 - 返回值:整個鏈式命令的返回值等于最后一個成功執行的命令返回值;若中途失敗,則返回失敗的那條命令的返回值。
- 適用場景:
- 多步驟“級聯”操作:如先下載包、再解壓、再安裝,任何一步失敗都要停止后續。
- 條件判斷:如先檢查網絡連通性,再執行更新;若檢查失敗,后續操作不執行。
5. 小結
- 作用:僅在前一命令成功時才執行下一命令。
- 適合場景:多步驟“必須成功才能往下做”的情況。
四、||
—— 邏輯或運算
前命令執行失敗了,才執行后面的命令
1. 語法格式
命令1 || 命令2 || 命令3 || …
解釋:只有當 命令1
返回非 0(失敗)時,才會執行 命令2
;若 命令1
成功(返回 0),則跳過 命令2
。依次類推:前一條失敗時才會繼續執行下一條。
2. 示例:
當前目錄下不存在 data 目錄
#!/bin/bash
cd data || pwd
pwd || cd /data
3. 輸出結果
- cd data 進入當前目錄下的 data 目錄
- 如果 data 目錄不存在(判斷返回非 0),才執行
pwd
;
Tip:為了邏輯更清晰,shell腳本中通常會寫成
if … else
結構,避免單行邏輯混淆。后續我會出條件判斷文章,一步一步來哦~
4. 小結
- 作用:僅在前一命令失敗時才執行下一命令。
- 適合場景:針對“異常/失敗”進行補救、日志記錄、報警通知等。
五、三者結合使用示例
在實際腳本中,常將 ;
、&&
、||
混合使用,實現更靈活的流程控制。下面示例演示:
- 部署
Tomcat 9.0.105
; - 下載地址:
https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.100/bin/apache-tomcat-9.0.100.tar.gz
- 工作目錄:
/data/web-service
- 日志路徑:
/data/web-service/logs/catalina.out
- 當然如果你想下載
tomcat 8、10、11
只需要替換DOWNLOAD_URL
變量中的數字即可
#!/bin/bash
# 定義變量
WORK_DIR="/data/web-service" #定義工作目錄變量
TOMCAT_VERSION="9.0.100" #定義tomcat小版本變量
TAR_NAME="apache-tomcat-${TOMCAT_VERSION}.tar.gz" #定義tomcat下載包變量
DOWNLOAD_URL="https://archive.apache.org/dist/tomcat/tomcat-9/v${TOMCAT_VERSION}/bin/${TAR_NAME}" #定義tomcat下載路徑,以及大版本,如果想下載tomcat8,直接把這里9改成8,然后修改對應的小版本號LOG_DIR="${WORK_DIR}/logs" #定義日志目錄
LOG_FILE="${LOG_DIR}/catalina.out"# 創建工作目錄和日志目錄
mkdir -p "$WORK_DIR" "$LOG_DIR" && echo "【創建目錄】工作目錄和日志目錄已創建" || { echo "【錯誤】無法創建目錄"; exit 1; }
cd "$WORK_DIR" || { echo "【錯誤】無法進入 $WORK_DIR"; exit 1; }
echo "【開始部署】Tomcat ${TOMCAT_VERSION} 部署開始于 $(date '+%F %T')"# 清空舊日志文件
> "$LOG_FILE" && echo "【初始化】日志文件已清空" || echo "【警告】日志文件不存在或無法清空"# 檢查是否已有 Tomcat 目錄,有則刪除
[ -d "apache-tomcat-${TOMCAT_VERSION}" ] && rm -rf "apache-tomcat-${TOMCAT_VERSION}" && echo "【清理】舊版 Tomcat 已刪除" ; echo "【檢查】當前無舊版 Tomcat 或已清理完畢"# 下載 Tomcat(如果不存在)
if [ ! -f "$TAR_NAME" ]; thenecho "【下載】開始下載 Tomcat..."wget -q --show-progress "$DOWNLOAD_URL"if [ $? -eq 0 ]; thenecho "【下載】Tomcat 已下載成功"elseecho "【錯誤】下載失敗,請檢查網絡或 URL"exit 1fi
elseecho "【下載】安裝包已存在,跳過下載..."
fi# 解壓 Tomcat
tar -zxpf "$TAR_NAME" > /dev/null 2>&1 && echo "【解壓】Tomcat 解壓成功" || { echo "【錯誤】解壓失敗,請檢查壓縮包"; exit 1; }# 啟動 Tomcat(后臺運行),輸出重定向到日志文件
./apache-tomcat-${TOMCAT_VERSION}/bin/startup.sh >> "$LOG_FILE" 2>&1 &
if [ $? -eq 0 ]; thenecho "【啟動】Tomcat 已啟動(后臺運行)"
elseecho "【錯誤】啟動失敗,請查看日志文件"exit 1
fi# 等待幾秒確保進程已經啟動
sleep 3# 輸出 Tomcat 進程信息
PID=$(ps -ef | grep java | grep "apache-tomcat-${TOMCAT_VERSION}" | awk '{print $2}')
if [ -n "$PID" ]; thenecho "【狀態】Tomcat 已運行,PID: $PID"
elseecho "【警告】未找到 Tomcat 進程,請檢查日志"
fiecho "【完成】部署流程結束于 $(date '+%F %T')"
要點解析:
- 第1步 用
||
判斷目錄是否存在,否則創建;再用&&
打印日志。- 第2步 用
&&
判斷cd
成功與否;失敗則用大括號{ … }
打印日志并退出。
六、常見誤區與注意事項
-
不加大括號導致邏輯混淆
cmd1 && cmd2 || cmd3
-
含義:如果
cmd1
成功,才會執行cmd2
;但無論cmd1
或cmd2
哪一個失敗,都會執行cmd3
。 -
若想實現“僅當
cmd1
成功且cmd2
失敗時才cmd3
”,需加大括號:cmd1 && { cmd2 || cmd3; }
-
-
分號與換行的等價性
cmd1; cmd2
等同于:
cmd1 cmd2
僅是寫法不同。分號適合一行寫多個短命令;若邏輯復雜,推薦換行并加注釋。
-
混合使用時要注意優先級
- Shell 會先解析
&&
、||
,最后處理;
。 - 當同時出現
&&
、||
、;
時,建議適當用“換行 + 大括號”來讓邏輯更清晰,避免歧義。
- Shell 會先解析
七、小白友好的命令對照表
操作符 | 含義 | 示例 | 適用場景 |
---|---|---|---|
; | 無條件順序執行 | echo A ; echo B ; echo C | 不關心命令是否成功,只要全部都執行一次 |
&& | 成功則繼續執行 | mkdir /tmp/dir && echo "創建成功" | 僅在前一步成功時才做后續操作 |
|| | 失敗則繼續執行 | cp A B || echo “復制失敗” | 用于失敗補救、日志記錄、報警通知 |
八、運維示例腳本:一鍵日志輪轉與備份
下面附上一個可直接拿來使用的運維腳本,通過 ;
、&&
、||
三種方式,實現對指定服務日志的輪轉、壓縮、備份,并保留最近 7 天的歷史。適用于 CentOS/Ubuntu 等常見 Linux 發行版。
腳本功能概覽
- 停止目標服務
- 將日志文件按日期重命名并壓縮備份到指定目錄
- 刪除 7 天前的舊備份
- 啟動目標服務
- 將執行結果寫入操作日
腳本下載方式,關注公眾號【安全日記Pro】,進入發送消息,點擊shell菜單,獲取腳本
📝 腳本使用說明
-
保存腳本
將以上內容保存為log_rotate_backup.sh
,并賦予可執行權限:chmod +x log_rotate_backup.sh
-
執行腳本示例
sudo sh log_rotate_backup.sh \tomcat "/var/log/tomcat/access.log" \"/backup/logs/tomcat" "/var/log/tomcat/rotate.log"
- 腳本會對
/var/log/tomcat/access.log
進行輪轉備份, - 備份文件存放在
/backup/logs/tomcat/2025-06/
目錄下, - 并將操作記錄寫入
/var/log/tomcat/rotate.log
。
- 腳本會對
-
定時執行(Crontab 可選)
可將腳本加入 crontab,實現每日自動輪轉。例如每天凌晨 1 點執行:#腳本路徑根據你實際情況填寫 0 1 * * * /usr/local/bin/log_rotate_backup.sh \tomcat "/var/log/tomcat/access.log" \"/backup/logs/tomcat" "/var/log/tomcat/rotate.log"
九、結語與小白學習建議
-
多練、多試
- 親手在終端嘗試不同的
;
、&&
、||
組合,觀察$?
的返回值和后續命令的執行情況,體驗它們的執行邏輯。
- 親手在終端嘗試不同的
-
使用
set -e
(可選)- 在腳本開頭添加
set -e
,可以讓腳本在任意一步出現非 0 返回值時立即退出。但要注意與||
、&&
的混用可能導致流程不如預期,初學者可先不加,待熟悉后再靈活運用。
- 在腳本開頭添加
-
日志與錯誤處理很關鍵
- 像示例腳本一樣,將執行結果寫到日志文件,并在失敗時發送報警或退出腳本,是做好運維腳本的關鍵。
-
牢記返回值判斷
- 在 Shell 中,返回值 0 = 成功,非 0 = 失敗。掌握這一點,就能自然而然地運用
&&
、||
進行流程控制。
- 在 Shell 中,返回值 0 = 成功,非 0 = 失敗。掌握這一點,就能自然而然地運用
本篇小結
;
:無條件順序執行,所有命令都會嘗試執行。&&
:前一步成功時才執行下一步,適合級聯式操作。||
:前一步失敗時才執行下一步,適合“失敗補救”或“日志/報警”。- 混合使用時要加大括號或換行,避免邏輯歧義。