命令分隔與順序執行
| 符號 | 名稱 | 行為 | 範例 |
; | 順序執行 | 無條件依次執行,互不影響返回值 | cd /tmp; ls; pwd |
&& | 邏輯 AND | 前命令成功(退出碼 0)才執行後命令 | make && make install |
|| | 邏輯 OR | 前命令失敗(非 0)才執行後命令 | ping -c1 host || echo "down" |
管道:進程間通訊橋樑
cmd1 | cmd2 # cmd1 stdout → cmd2 stdin
cmd1 2>&1 | cmd2 # 合併 stderr 進管道
cmd1 |& cmd2 # Bash 4+ 簡寫(同上)
管道創建子 Shell,cmd2 在子進程中運行,其變量修改不影響父 Shell。
命令分組:當前 Shell 上下文
| 語法 | 範圍 | 變量隔離 | 典型用途 |
{ cmd1; cmd2; } | 當前 Shell | 無(共享變量) | 重定向整組輸出、函數體 |
( cmd1; cmd2 ) | 子 Shell | 有(獨立環境) | 臨時 cd、umask、ulimit、避免污染 |
分組實戰範例
# 當前 Shell 分組:統一重定向
{ echo "Start"; ./build.sh; echo "End"; } > build.log 2>&1
# 子 Shell:臨時進入目錄執行
( cd /tmp && tar -czf backup.tar.gz /data )
# 子 Shell 保護變量
var=global
( var=local; echo "sub: $var" )
echo "parent: $var" # 輸出 global
控制結構:條件與循環
# if 條件
if cmd; then ...; elif cmd; then ...; else ...; fi
# case 模式匹配
case $var in
pattern) commands ;;
*) default ;;
esac
# for 循環
for f in *.txt; do echo "$f"; done
for ((i=0;i<10;i++)); do echo $i; done
# while 循環
while read line; do process "$line"; done < file
# until 循環
until ping -c1 host; do sleep 5; done
返回值與退出碼
$?:上一命令退出碼(0=成功,1-255=失敗)
${PIPESTATUS[@]}:管道中每個命令的退出碼陣列
set -e:遇非零即退出(腳本嚴格模式)
set -o pipefail:管道任一失敗即整體失敗
異步與併發
cmd & # 後台運行,返回 PID
pid=$! # 獲取最後後台進程 PID
wait $pid # 等待特定後台進程
wait # 等待所有後台進程
# 併發控制:xargs -P
printf '%s\n' *.log | xargs -P4 -I{} gzip {}
# GNU parallel
parallel -j4 gzip ::: *.log
實戰組合招
| 場景 | 命令 |
| 部署腳本:任一步驟失敗即停止 | set -e; ./build.sh && ./test.sh && ./deploy.sh |
| 備份:壓縮並校驗 | tar -czf backup.tar.gz /data && sha256sum backup.tar.gz > backup.sha256 |
| 健康檢查:重試 3 次 | for i in {1..3}; do curl -sf https://host/health && break || sleep 2; done |
| 日誌分析:錯誤計數 | grep -c "ERROR" app.log || echo "0" |
| 安全清理:確認後刪除 | rm -i $(find /tmp -name "*.tmp" -mtime +7) |
常見坑點
cmd1 && cmd2 || cmd3 ≠ if-else:若 cmd2 失敗,cmd3 也會執行
- 管道中
set -e 不生效,需 set -o pipefail
- 子 Shell 中
cd、export 不影響父 Shell
var=value cmd 僅影響該命令環境,非持久化