工具 Linux

一行串起多条命令:Linux 中 ;、&& 与 || 的执行语义详解

有的时候执行一些简单指令,总不想分好几次输入。利用 Shell 的命令串联能力可以方便地一次执行多个命令,但 ;、&&、|| 三种写法在出错时的行为完全不同,用错了轻则白跑,重则脏数据。这篇文章用同一个例子把三者的语义讲清楚。

前置知识:命令的退出码

要理解三种分隔符,先要知道 Linux 下每条命令执行完都有一个退出码(exit code):0 表示成功,非零表示失败。可以用 echo $? 查看上一条命令的退出码。

;、&&、|| 的区别,本质上就是根据前一条命令的退出码,决定后面还跑不跑。

连续不中断执行:;

用 ; 分隔的命令会依次全部执行,中间出错也不会中断后面的命令:

bash
mkdir test; mkdir test; rmdir test

第一次执行时:

  1. mkdir test 成功,创建目录;
  2. mkdir test 报错(目录已存在),但没关系;
  3. rmdir test 照常执行,把目录删掉。

最终结果:命令全部跑完,test 目录不存在。

适用场景:几个互不依赖的操作打包执行,比如批量清理、一系列互不影响的查询。

出错即停止:&&

用 && 分隔的命令,前面的成功才继续,一旦出错立即中止:

bash
mkdir test && mkdir test && rmdir test

这回在第二个 mkdir test 处就中止了,rmdir 不会执行,test 目录残留。

适用场景:步骤之间有依赖关系的流水线,最经典的就是「编译成功才部署」:

bash
make && make install

这是 && 最重要的价值——防止上一步失败时,下一步在错误状态上继续执行。

一次成功即停止:||

用 || 分隔的命令,前面的失败才继续,直到有一次成功立即停止:

bash
mkdir test || mkdir test || mkdir test
  • 第一次执行:第一条就成功,后面两条不执行;
  • 换成 mkdir test || mkdir test || mkdir test || mkdir test 并在 test 已存在时执行:前两条都报错,第三条也报错,最后一条才成功(如果前面的命令已把目录建好,逻辑同理)。

适用场景:提供备选方案(fallback),典型的例子是「目录不存在才创建」:

bash
test -d /data/logs || mkdir -p /data/logs

以及「本地没有配置文件就复制一份默认的」:

bash
cp config.local.yml config.yml 2>/dev/null || cp config.example.yml config.yml

三者对比速查

分隔符前面成功时前面失败时典型用途
;继续执行继续执行无依赖操作打包
&&继续执行停止有依赖的流水线
``停止

组合使用也很常见,比如「成功打日志、失败打告警」:

bash
./run_job.sh && echo "job done" || echo "job failed"

写在后面

这套语义在脚本里还可以用 set -e(出错即退出整个脚本)进一步收口,但交互式命令行里,; / && / || 依然是最常用的三件套。理解「退出码驱动」这个本质,比背案例更重要——任何分隔符的行为,都可以从前一条命令的退出码推导出来。