路径、系统目录与注释

# (井号)

注释屏蔽

位于行首或命令后(需有空格分隔),其后内容仅作说明,不被执行。

# 这是一个单行注释,整行都不会被执行
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            

正则单字匹配

grepsedawk 等支持正则表达式的工具中,. 匹配任意单个字符。

# 在文件中查找 "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 /

/ (正斜线):算术运算中的除法

$(( )) 结构或 exprlet 命令中,代表除法。

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 "执行完毕"

单行控制结构换行符

在编写 ifforwhile 等控制语句时,如果不想写成多行,= 就是完美的语句分隔符,它在单行脚本中等同于换行。

# 单行 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 - 快速切回上一次的工作目录。

标准输入截获:在部分命令(如 cattar)中代表直接截获键盘的标准输入流。

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)合并重定向。