当前位置:首页>Linux>Linux 从0到1 : 11 · 命令链接与 Shell 脚本

Linux 从0到1 : 11 · 命令链接与 Shell 脚本

  • 2026-09-10 08:47:23
Linux 从0到1 : 11 · 命令链接与 Shell 脚本
     欢迎来到罐子的实验室
    今天来学习 命令链接与 Shell 脚本

    本次目标

把零散的命令组合起来,从「打一行跑一行」升级到「写一个脚本自动跑一堆命令」。这是自动化的起点。

学完你能做什么:

  • 用 ;&&|| 把命令串成一条
  • 把命令写进 .sh 文件,用 bash 执行
  • 让脚本变可执行(shebang + chmod +x)
  • 给脚本传参数($1$2...)
  • 用 if/elif/else 做条件判断

1. 为什么要把命令连起来

你每天可能重复跑这样一组命令:

user@host:~$ cd ~/projectuser@host:~$ git pulluser@host:~$ makeuser@host:~$ ./run_tests

四条命令、四次回车。如果能写成「跑完 pull 再 make 再测试」一条命令,多省事。Shell 给了好几种「连接命令」的方式。


2. 分号 ;:依次执行

最简单:用 ; 把几条命令放一行,依次执行(不管前一条成不成功):

user@host:~$ echo first; echo second; echo thirdfirstsecondthird

等价于分三次敲回车。A ; B 表示「先跑 A,跑完(不管成败)跑 B」。

动手练习 1:串联

任务:用分号把 date、whoami、pwd 三条命令串成一行执行。

参考答案:

user@host:~$ date; whoami; pwdSun Jun 30 18:00:00 UTC 2024user/home/user

3. &&:成功才继续

A && B 表示「只有 A 成功了(退出码为 0)才跑 B」。这是「与」逻辑。

user@host:~$ mkdir newdir && cd newdir# 创建成功才进去user@host:~/newdir$user@host:~/newdir$ cd /tmpuser@host:/tmp$ cd /nope && echo OK# cd 失败,echo 不跑bash: cd: /nope: No such file or directoryuser@host:/tmp$

非常适合「前一步是后一步前提」的场景:编译成功才部署、下载成功才解压。

动手练习 2:条件串联

任务:写一条命令——「如果 /etc/passwd 存在,就打印 exists」。

思路引导:test -f 文件 在文件存在时返回 0;&& 接 echo。

参考答案:

user@host:~$ test -f /etc/passwd && echo existsexists

4. ||:失败才继续

A || B 表示「A 失败了(退出码非 0)才跑 B」。这是「或」逻辑——A 成功就用 A,A 不行就上 B。

经典用途:给命令配一个「备用方案」。

user@host:~$ cd /nope || echo ”目录不存在,留在原地”bash: cd: /nope: No such file or directory目录不存在,留在原地
user@host:~$ grep error logfile || echo ”没找到 error,一切正常”没找到 error,一切正常# grep 找不到时退出码非 0,于是 echo 跑

动手练习 3:容错

任务:写一条命令——「尝试 cat config.txt,如果文件不存在就打印 用默认配置」。

参考答案:

user@host:~$ cat config.txt || echo ”用默认配置”用默认配置

💡 && 和 || 可以组合:A && B || C = A 成功跑 B,B 又失败的话跑 C。但组合复杂时建议用后面的 if。


5. 你的第一个脚本

把多条命令写进一个文件,就成了 Shell 脚本。按惯例用 .sh 后缀。

user@host:~$ cd ~/linux-practiceuser@host:~/linux-practice$ cat > hello.sh <<EOFecho Helloecho WorlddateEOF

(<<EOF ... EOF 叫「here-document」,让你一次输入多行直到遇到 EOF。也可以用编辑器如 nano hello.sh 来写。)

然后用 bash 运行它:

user@host:~/linux-practice$ bash hello.shHelloWorldSun Jun 30 18:00:00 UTC 2024

bash hello.sh 的意思是:启动 bash,让它从 hello.sh 读命令执行,而不是从键盘读。

动手练习 4:写个问候脚本

任务:写一个 greet.sh,依次打印「欢迎」「当前用户」「当前时间」。

思路引导:文件里写三行 echo/whoami/date。

参考答案:

user@host:~/linux-practice$ cat > greet.sh <<'EOF'echo 欢迎whoamidateEOFuser@host:~/linux-practice$ bash greet.sh欢迎userSun Jun 30 18:00:00 UTC 2024

6. 让脚本「可执行」

每次都 bash greet.sh 太啰嗦。如果给脚本加执行权限,就能直接 ./greet.sh 跑(→ chmod 详见《模块 10》):

user@host:~/linux-practice$ ls -l greet.sh-rw-r--r-- ... greet.sh# 没有执行权限user@host:~/linux-practice$ chmod +x greet.shuser@host:~/linux-practice$ ls -l greet.sh-rwxr-xr-x ... greet.sh# 有了 xuser@host:~/linux-practice$ ./greet.sh欢迎...

注意必须写 ./greet.sh(带 ./),不能只写 greet.sh——出于安全考虑,Linux 不会在当前目录找命令,必须明确路径。这点《模块 13》会详细讲。


7. shebang:告诉系统用谁解释

./greet.sh 能跑,是因为 Linux 默认用当前 Shell解释它。但更可靠的做法是在脚本第一行写 shebang——告诉内核「请用这个解释器运行我」:

#!/bin/bashecho 欢迎whoamidate

#!/bin/bash 的意思是「用 /bin/bash 来执行本文件」。当 Linux 看到文件开头是 #!,就把后面那行当作解释器路径,相当于自动执行 /bin/bash 脚本路径。

💡 shebang 必须是第一行,前面不能有空行。常见值:

  • #!/bin/bash
     —— bash 脚本
  • #!/usr/bin/env bash
     —— 更可移植(用 env 找 bash)
  • #!/usr/bin/python3
     —— Python 脚本
  • #!/bin/sh
     —— POSIX sh,更兼容但功能少

动手练习 5:加 shebang

任务:给 greet.sh 加上 shebang,确认 ./greet.sh 仍能正常跑。

参考答案:

user@host:~/linux-practice$ nano greet.sh# 或用别的编辑器,在第一行加 #!/bin/bash# 编辑后内容:# #!/bin/bash# echo 欢迎# whoami# dateuser@host:~/linux-practice$ ./greet.sh欢迎user...

8. 给脚本传参数

脚本可以接受命令行参数,用特殊变量读取(→ 变量详见《模块 08》):

变量
含义
$0
脚本自己的名字
$1
$2$3 ...
第 1、2、3 个参数
$#
参数总个数
$@
所有参数(每个独立)
"$*"
所有参数(合成一个串)

例子:

#!/bin/bashecho ”脚本名: $0”echo ”第一个参数: $1”echo ”第二个参数: $2”echo ”共 $# 个参数”

运行:

user@host:~/linux-practice$ ./args.sh alice bob carol脚本名: ./args.sh第一个参数: alice第二个参数: bob共 3 个参数

💡 给 $1 等加引号:"$1",防止参数含空格时被拆词。

动手练习 6:参数脚本

任务:写个 reverse.sh,接受两个参数,逆序输出(先输第二个再输第一个)。

思路引导:echo "$2 $1"。

参考答案:

#!/bin/bashecho ”$2 $1”
user@host:~/linux-practice$ ./reverse.sh hello worldworld hello

9. 条件判断:if

if 让脚本根据情况做不同事。基本语法:

if [ 条件 ]; then 命令1 命令2fi

注意几个坑:

  • [
     后面、] 前面必须有空格:[ "$1" = "x" ]。
  • if
    、then、fi 要么换行要么用 ; 分隔。
  • 结束符是 fi(if 倒过来写),不是 endif。
#!/bin/bashif [ ”$1” = ”ping” ]; then echo pongfi
user@host:~/linux-practice$ ./ping.sh pingponguser@host:~/linux-practice$ ./ping.sh hello# 没匹配,啥也不输出

💡 = 是字符串比较。数字比较用 -eq-ne-lt-gt(等于/不等于/小于/大于)。更多见 help test。

[ ] 里常用的判断:

写法
含义
[ -f 文件 ]
文件存在且是普通文件
[ -d 目录 ]
目录存在
[ -e 路径 ]
路径存在(不论类型)
[ -r 文件 ]
可读
[ -z "$X" ]
字符串 X 为空
[ -n "$X" ]
字符串 X 非空
[ "$A" = "$B" ]
两字符串相等
[ "$A" != "$B" ]
不等

动手练习 7:简单的 if

任务:写个脚本,接受一个参数。如果参数是 pwn,输出 college;否则什么都不输出。

参考答案:

#!/bin/bashif [ ”$1” = ”ko” ]; then echo okfi
user@host:~/linux-practice$ ./chk.sh kookuser@host:~/linux-practice$ ./chk.sh foo# 无输出

常见错误:

  • ❌ [$1 = "ko"](没空格)→ 语法错误。[ 和 ] 两边都要空格。
  • ❌ if [...] then(没分号也没换行)→ 要 if ... ; then 或换行。

10. else 和 elif

else 处理「否则」:

if [ ”$1” = ”hello” ]; then echo Hielse echo 我不认识你fi

elif(else if)处理多个分支:

if [ ”$1” = ”hello” ]; then echo hielif [ ”$1” = ”hi” ]; then echo helloelif [ ”$1” = ”learn” ]; then echo linuxelse echo unknownfi

注意每个 elif 后面都要 then,else 后面不要 then,最后用 fi 收尾。

动手练习 8:多分支脚本

任务:写个脚本,参数是 start 时输出「启动中」,是 stop 时输出「停止中」,是 status 时输出「运行中」,其他情况输出「未知命令」。

参考答案:

#!/bin/bashif [ ”$1” = ”start” ]; then echo 启动中elif [ ”$1” = ”stop” ]; then echo 停止中elif [ ”$1” = ”status” ]; then echo 运行中else echo 未知命令fi
user@host:~/linux-practice$ ./svc.sh start启动中user@host:~/linux-practice$ ./svc.sh xxx未知命令

11. 实战:一个有用的脚本

把所学串起来,写个自动备份脚本backup.sh:

#!/bin/bash# 用法: ./backup.sh 要备份的目录 备份存放目录SRC=”$1”DST=”$2”# 检查参数个数if [ $# -ne 2 ]; then echo ”用法: $0 <源目录> <备份目录>” exit 1fi# 检查源目录是否存在if [ ! -d ”$SRC” ]; then echo ”错误: 源目录 $SRC 不存在” exit 1fi# 创建备份目录(如果不存在)mkdir -p ”$DST”# 生成带时间戳的备份文件名ARCHIVE=”$DST/backup-$(date +%Y%m%d-%H%M%S).tar.gz”# 打包压缩tar -czf ”$ARCHIVE” -C ”$SRC” . && echo ”备份完成: $ARCHIVE” || echo ”备份失败”

运行:

user@host:~/linux-practice$ chmod +x backup.shuser@host:~/linux-practice$ ./backup.sh ~/Documents ~/backups备份完成: /home/user/backups/backup-20240630-180000.tar.gz

这个脚本用到了:参数($1/$2/$#)、if 判断、&&/||、命令替换 $(date)、mkdir -p、tar——前 10 个模块的精华都在里面了。

动手练习 9:改造它

任务:把 backup.sh 改成——如果备份成功,再额外用 ls -lh 显示生成的备份文件大小。

思路引导:在 && 后面加 && ls -lh "$ARCHIVE"。

参考答案:

把最后那行改成:

tar -czf ”$ARCHIVE” -C ”$SRC” . && echo ”备份完成” && ls -lh ”$ARCHIVE” || echo ”备份失败”

本模块速查表

操作
含义
A ; B
依次执行(不管 A 成败)
A && B
A 成功才跑 B
A || B
A 失败才跑 B
bash 脚本.sh
用 bash 执行脚本
chmod +x 脚本
加执行权限
./脚本.sh
直接执行(需有 x 权限)
#!/bin/bash
shebang,脚本第一行

脚本里的特殊变量

变量
含义
$0
脚本名
$1
$2 ...
位置参数
$#
参数个数
$@
所有参数
$?
上条命令退出码

if 语法

if [ 条件 ]; then ...elif [ 条件 ]; then ...else ...fi

铁律:[] 两边空格;then 前用 ; 或换行;fi 收尾。


下一步

你的脚本里如果有个耗时任务(比如长时间下载),万一 SSH 断了,脚本就死了——所有工作丢失。下一模块教你用「终端复用器」让任务脱离终端存活。

最新文章

随机文章