路径、系统目录与注释
# (井号)
注释屏蔽
位于行首或命令后(需有空格分隔),其后内容仅作说明,不被执行。
# 这是一个单行注释,整行都不会被执行
echo "Hello, World!"
ls -l # 这是一个行尾注释,仅注释掉 # 后面的内容
# 注意:如果 # 被引号包裹,它就失去了注释的作用,变成了普通字符
echo "My favorite hashtag is #Linux"
解释器声明
位于脚本绝对的第一行,内核会根据它来决定使用哪个解释器来执行该脚本。
#!/bin/bash
# 明确指定使用 /bin/bash 来执行脚本
# 或者使用更具可移植性的写法(推荐):
#!/usr/bin/env python3
# 去系统环境变量中寻找 python3 解释器来执行
计算变量/数组的长度
在变量替换中,# 可以用来获取字符串的字符数量,或者数组的元素个数。
my_str="Hello"
echo "字符串长度为: ${#my_str}" # 输出: 5
my_array=(apple banana cherry)
echo "数组元素个数为: ${#my_array[@]}" # 输出: 3
字符串截取(“掐头”)
配合 ${变量#匹配规则} 或 ${变量##匹配规则},可以删除字符串左侧符合规则的内容。
filename="backup.tar.gz"
# 一个 # 代表最短匹配(非贪婪),删除左侧第一个 . 及之前的内容
echo ${filename#*.} # 输出: tar.gz
# 两个 ## 代表最长匹配(贪婪),删除左侧最后一个 . 及之前的内容
echo ${filename##*.} # 输出: gz
获取传入参数的个数
在脚本或函数中,$# 是一个特殊的内置变量,代表传递给脚本或参数的总个数。
#!/bin/bash
# 假设执行: ./script.sh arg1 arg2 arg3
echo "你一共传入了 $# 个参数。" # 输出: 你一共传入了 3 个参数。
~ (波浪号):路径跳转与目录栈的快捷键
家目录定位
单独使用 ~ 代表当前执行用户的 Home 目录;~user 指向特定用户的家目录。
# 快速回到当前用户的家目录(等同于直接输入 cd)
cd ~
# 复制文件到当前用户的下载目录
cp file.txt ~/Downloads/
# 切换到 root 用户的家目录(通常是 /root,需要相应权限)
cd ~root
工作路径记录
~+ 等同于 $PWD(当前所在目录);~- 等同于 $OLDPWD(上一次所在的目录)。这在编写自动化脚本需要频繁切换路径时非常有用。
# 假设你当前在 /var/log 目录下
echo "当前目录: ~+" # 输出: 当前目录: /var/log
# 现在切换到 /tmp 目录
cd /tmp
# 使用 ~- 快速回到上一个目录 (/var/log)
cd ~-
# pwd 将显示 /var/log
快速创建备份文件约定
虽然这不是 Shell 语法级别的硬性规定,但在 Linux 生态(尤其是 Vim 或 Emacs 编辑器中),~ 常被追加在文件末尾作为备份文件的扩展名。
# 许多文本编辑器在修改 config.conf 后,会自动生成一个旧版本的备份:
ls -l config.conf*
# 可能会看到:
# config.conf
# config.conf~ <-- 这通常是修改前的备份文件
```没问题!你总结的基础概念非常准确。这两个符号在 Shell 脚本中虽然基础,但实际上还隐藏了不少非常实用的高阶技巧。
我来为你梳理并补充完善,并为每个场景配上直接可用的代码示例。
. (点号)
路径指示与执行
单个 . 代表当前工作目录,双点 .. 代表上一级目录。此外,配合 / 使用时(./),它是执行当前目录下脚本的标准姿势(为了安全,Linux 默认不会在当前目录查找可执行文件)。
cd .. # 返回上一级目录
cp ~/file.txt . # 将家目录的文件复制到【当前目录】
# 执行当前目录下的脚本
./script.sh
隐藏文件属性
在 Linux/Unix 系统中,文件名以 . 开头即被视为隐藏文件(如配置文件)。
# 普通的 ls 看不到隐藏文件
ls
# 必须加上 -a (all) 参数才能看到,例如 .bashrc, .profile
ls -a
正则单字匹配
在 grep、sed、awk 等支持正则表达式的工具中,. 匹配任意单个字符。
# 在文件中查找 "c-t",中间可以是任意一个字符 (如 cat, cut, cbt)
grep "c.t" filename.txt
环境引入 (Source 命令的简写)
在 Shell 脚本中,位于行首且后接空格的 . 等同于 source 命令。它用于在当前 Shell 环境中读取并执行另一个脚本中的命令(常用于加载变量配置),而不是启动一个子 Shell 去执行。
# 假设 config.sh 中写了 DB_USER="admin"
# 引入 config.sh 中的变量
. ./config.sh # 等同于 source ./config.sh
echo "数据库用户是: $DB_USER" # 输出: 数据库用户是: admin
/ 与 \ (斜线系)
/ (正斜线):路径与根目录
位于路径开头表示根目录,在中间表示层级分隔符。
# 从根目录 (/) 开始的绝对路径
cd /var/log/nginx
# 根目录本身
ls /
/ (正斜线):算术运算中的除法
在 $(( )) 结构或 expr、let 命令中,代表除法。
total=10
# 计算 10 除以 2
echo $(( total / 2 )) # 输出: 5
/ (正斜线):变量的字符串替换
在变量操作中,斜杠是一个非常强大的替换工具!
${var/old/new}:替换第一个匹配的字符串。${var//old/new}:替换所有匹配的字符串。
text="I love apple, apple is tasty."
# 单个 / 替换第一次出现的 apple
echo ${text/apple/linux} # 输出: I love linux, apple is tasty.
# 双 // 替换所有出现的 apple
echo ${text//apple/linux} # 输出: I love linux, linux is tasty.
\ (反斜线):转义与特殊含义屏蔽
紧跟在 \ 后面的特殊字符会变成普通字符,失去系统赋予的特殊含义(比如 $, *, " 等)。
price=100
# 如果不加 \,系统会尝试解析变量 $price。加上 \ 后,$ 就变成了普通字符。
echo "The cost is \$price" # 输出: The cost is $price
\ (反斜线):续行符
当一条长命令在一行写不下时,在行尾加上 \ 可以让命令在下一行继续(注意 \ 后面直接敲回车,不能有空格)。
# 将长命令拆分成多行,提高可读性
docker run -d \
--name web_server \
-p 8080:80 \
-v /host/data:/container/data \
nginx:latest
\ (反斜线):配合 echo 激活控制字符
结合 echo -e,反斜杠可以用来输出特定的格式符,如 \n(换行)、\t(制表符/Tab)。
# 输出带换行和制表符的文本
echo -e "Name:\tAlice\nAge:\t25"
# 输出结果:
# Name: Alice
# Age: 25
命令执行、控制与逻辑
; 与 ;; (分号)
命令连续执行
分隔多条命令,无视前置命令的成功与否,按顺序依次执行。
# 无论 /tmp 目录能否进去,都会尝试执行后面的创建和打印命令
cd /tmp ; mkdir test_dir ; echo "执行完毕"
单行控制结构换行符
在编写 if、for、while 等控制语句时,如果不想写成多行,= 就是完美的语句分隔符,它在单行脚本中等同于换行。
# 单行 for 循环
for i in {1..3}; do echo "这是第 $i 次循环"; done
# 单行 if 判断
if [ -f "config.txt" ]; then echo "文件存在"; else echo "文件缺失"; fi
分支终止符 (;;)
专用于 case 语句,作用类似于 C/Java 语言 switch 语句中的 break。匹配到对应条件执行完毕后,遇到 ;; 就会跳出整个 case 块。
read -p "请输入 start 或 stop: " action
case $action in
start)
echo "服务正在启动..."
# 启动命令...
;; # 遇到 ;; 退出 case
stop)
echo "服务正在停止..."
;;
*)
echo "未知指令!"
;;
esac
贯穿与继续匹配
标准的 ;; 会直接打断分支,但有时候我们需要类似“向下贯穿”的效果:
;&:执行完当前匹配块后,不加判断直接执行下一个匹配块的代码(Fall-through)。;;&:执行完当前匹配块后,继续去判断后面的模式是否匹配,如果匹配则接着执行。
# 测试 ;& 贯穿效果
char="a"
case $char in
a)
echo "匹配到了 a"
;& # 不退出,强行继续执行下一个块(b)的代码
b)
echo "连带着执行了 b"
;;
esac
| (管道符)
数据流传递
将左侧命令的标准输出 (stdout) 变成右侧命令的标准输入 (stdin)。
# 查看系统进程 -> 过滤出 nginx -> 统计行数
ps aux | grep "nginx" | wc -l
标准错误一并传递
普通的 | 只能传递标准输出 (stdout),如果左边的命令报错了,错误信息 (stderr) 会直接打印到屏幕上,而不会传给右边。 使用 |&(等价于 2>&1 |),可以将正确输出和报错信息一起交给下一个命令处理。
# 假设 /non_existent_dir 不存在,ls 会产生错误信息
# 普通管道无法用 grep 抓住错误信息:
ls /non_existent_dir | grep "No such file" # 屏幕上依然会直接显示报错,grep 未生效
# 使用 |& 即可抓住错误信息进行处理:
ls /non_existent_dir |& grep "No such file" # 成功通过 grep 匹配到错误信息
管道状态陷阱 (PIPESTATUS 数组)
多条命令通过管道连接时,系统默认 $?(上一条命令的退出状态码)只看管道最后一条命令的结果。即使前面命令失败了,只要最后一个命令成功,脚本就会以为整个组合都成功了。
# cat 一个不存在的文件肯定会失败,但 grep 收不到东西也不会报错,退出码为 1
cat no_exist.txt | grep "keyword"
# 使用 ${PIPESTATUS[@]} 数组,可以获取管道中【每一条命令】的执行状态码
echo "完整状态码: ${PIPESTATUS[@]}"
# 输出可能类似于: 完整状态码: 1 1 (代表 cat 失败了,grep 也失败了)
! (惊叹号)
逻辑非运算
条件判断中表示“不等于”(如 !=);正则/通配符中表示排除(如 [!0-9])。
历史命令调用
!1038 执行历史第1038条记录;!! 执行上一条命令;!$ 提取上一条命令的最后一个参数。
: (冒号)
空指令/占位符
什么都不做,但永远返回成功状态 ($? = 0)。常用于配合重定向快速清空文件。
路径分隔符
在环境变量(如 $PATH 或 $CDPATH)中用于分隔多个不同的路径。
: > clear_me.txt # 高效清空或创建空文件
&、&& 与 || (逻辑与控制)
后台任务挂载 (&)
置于命令末尾,将该条指令直接放入后台运行,不阻塞当前终端。
逻辑与 (&&)
条件控制。前置命令成功执行后($? = 0),才会触发后续命令。
逻辑或 (||)
条件控制。前置命令执行失败后($? != 0),才会触发后续命令。
Bash
ls /dir || mkdir /dir && echo "目录已就绪"
变量、引号与运算
' '、" " 与 ` ` (引号系)
强引用 (' ')
纯字符串模式。屏蔽内部所有特殊符号(如 $、\)的作用。
弱引用 (" ")
防断词与通配符扩展,但允许解析变量和转义符。
命令替换 (` `)
执行反引号内的命令,将输出结果赋值给变量(等同于 $() )。
echo "Today is `date +%F`" # 输出带当前日期的字符串
$ (美元符系)
变量值提取 ($var)
获取指定变量内存放的值。
进程与状态查询
$? 获取上个命令的回传值(0为成功);$$ 获取当前 Shell 的 PID;$! 获取最后运行的后台进程 PID。
传入参数接收
$* 与 $@ 获取全部外部传参;$# 获取传递参数的总个数。
正则替换界定 (${})
用于变量的安全截取、替换以及默认值赋初值等高级操作。
* 与 ** (星号)
通配与正则扩展 (*)
通配符中匹配0到无穷多个任意字符;正则中指代前驱字符的0到多次重复。
算术运算
* 代表乘法(配合 expr 使用需加转义 \*);** 代表求幂(次方运算)。
+、-、%、= 等 (运算符)
加/减/取模 (+ - %)
算术操作。
等值/不等 (= == !=)
用于变量赋值或条件判断中的对比。
连字符特权 (-)
目录返回:cd - 快速切回上一次的工作目录。
标准输入截获:在部分命令(如 cat、tar)中代表直接截获键盘的标准输入流。
cat head.txt - tail.txt > out.txt
# 读取head后挂起,等待键盘(-)输入并按Ctrl+D结束,最后合并tail写入out
括号与正则匹配锚点
() 与 (()) (圆括号)
子 Shell 指令群 (())
产生 Subshell 执行指令,内部变量修改不会污染当前终端环境。
内置算术运算 ((()))
执行高效整数运算(+-*/%),支持变量自增/减,且允许内部存在空格。
(( a = 10 )) ; (( a++ ))
{} (大括号)
当前 Shell 代码块
不产生子 Shell,直接在当前环境执行指令群;也常作为匿名函数体。
字符集合展开
用于字符串或路径的批量组合与快速生成。
mkdir {userA,userB}-{home,bin} # 快速展开为4个组合目录
[] 与 [[]] (中括号)
条件测试与字符集 ([])
充当流程判断式的外壳;在通配符中代表匹配括号内的任意单字符。
高级逻辑测试 ([[]])
增强型判断,允许在内部直接书写 &&、|| 以及进行更复杂的正则匹配。
? (问号)
单字通配
在文件名扩展中匹配任意且唯一的单个字符。
正则可选项
在扩展正则中,代表匹配0个或1个前驱字符。
^ 与 \< \> (匹配锚点)
行首定位 (^)
正则中匹配以该字符开头的行;在 [^] 内使用代表逻辑非(排除该字符)。
单词边界 (\< \>)
锁定完整单词进行匹配,防止由于子串重合导致的误匹配。
输入输出重定向
< 与 > (重定向符)
标准输出 (> / >>)
> 表示清除并覆盖写入;>> 表示在文件末尾追加写入。
标准输入 (< / <<)
< 将文件内容作为输入;<< EOF 开启多行交互输入,直到读取到 EOF 结束。
错误与流控制
2> 专职分离并输出报错信息;&> 将正确输出(1)与错误输出(2)合并重定向。