Shell 中有三种常用的命令连接符:&&||;,它们的执行逻辑完全不同。

三种连接符对比

连接符 执行条件 示例 说明
&& 前面成功才执行后面 cmd1 && cmd2 AND 逻辑
` ` 前面失败才执行后面
; 无条件执行后面 cmd1 ; cmd2 顺序执行

实例分析

问题示例

1
python -m A.py && python /tmp/A.py ; python -m B.py && python /tmp/B.py

执行流程

  1. 执行 python -m A.py

    • 成功 → 执行 python /tmp/A.py
    • 失败 → 跳过 python /tmp/A.py
  2. 无论上一步结果如何,执行 python -m B.py(因为 ;

    • 成功 → 执行 python /tmp/B.py
    • 失败 → 跳过 python /tmp/B.py

场景测试

场景 1:A.py 成功,B.py 失败

1
2
3
4
5
6
7
8
# A.py 返回 0 (成功)
# B.py 返回 1 (失败)

实际执行:
1. python -m A.py ✓
2. python /tmp/A.py ✓
3. python -m B.py ✗
4. python /tmp/B.py (跳过)

场景 2:A.py 失败,B.py 成功

1
2
3
4
5
6
7
8
# A.py 返回 1 (失败)
# B.py 返回 0 (成功)

实际执行:
1. python -m A.py ✗
2. python /tmp/A.py (跳过)
3. python -m B.py ✓
4. python /tmp/B.py ✓

常用模式

确保全部成功

1
2
# 任何一步失败都停止
cmd1 && cmd2 && cmd3

失败时执行备选

1
2
3
4
5
# cmd1 失败时执行 cmd2
cmd1 || cmd2

# 实际应用
wget https://example.com/file || curl -O https://example.com/file

无条件顺序执行

1
2
# 不管成功失败都继续
cmd1 ; cmd2 ; cmd3

组合使用

1
2
# 清理临时文件:尝试删除,失败也不影响后续
rm -rf /tmp/cache || true ; make build

在 K8s 中使用

Pod 启动脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
containers:
- name: app
image: python:3.9
command: ["/bin/sh", "-c"]
args:
- |
python -m setup && \
python -m migrate && \
python -m app

容错启动

1
2
# 尝试从配置文件加载,失败则使用默认配置
python -m load_config || python -m init_default_config ; python -m start

退出码说明

Shell 通过退出码判断命令成功失败:

退出码 含义
0 成功
1-255 失败

查看上一个命令的退出码:

1
echo $?

设置脚本在任何命令失败时退出:

1
2
3
4
5
#!/bin/bash
set -e # 遇到错误立即退出

cmd1
cmd2 # 如果 cmd1 失败,不会执行到这里

实用技巧

确保关键步骤成功

1
2
3
4
5
6
7
8
9
#!/bin/bash
set -e # 任何命令失败都退出

git pull && \
npm install && \
npm run build && \
npm test

echo "所有步骤成功完成"

日志记录

1
2
# 成功和失败都记录
cmd && echo "✓ cmd succeeded" || echo "✗ cmd failed"

超时控制

1
2
# 5 秒超时
timeout 5 long_running_cmd && echo "完成" || echo "超时或失败"

注意事项

  • set -e 模式下,||&& 会影响脚本是否退出
  • 管道命令 | 默认只检查最后一个命令的退出码,使用 set -o pipefail 检查所有
  • 在脚本中建议使用 set -euo pipefail 组合提高安全性

参考示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash
set -euo pipefail # 严格模式

# 准备环境
mkdir -p /tmp/build && cd /tmp/build

# 下载代码
git clone https://github.com/example/repo.git || {
echo "Git clone failed"
exit 1
}

# 构建和测试
cd repo && \
npm install && \
npm run build && \
npm test

echo "构建成功"