Shell 脚本中有一类特别重要的变量——位置参数变量。它们以 $
开头,专门用来接收和处理传给脚本的参数、命令执行状态、脚本自身信息等。在写 Shell 脚本时,正确理解和使用这些变量,是掌握脚本编程的基础。
在正式内容开始之前,我先给大家再次介绍一下shell脚本的执行吧,相信很多人不懂,其实我在开始写shell文章的时候已经说过了,但是讲的可能不是很细致,今天写这篇文章,我觉得有必要再次讲解一下了。
脚本开头的 shebang(如
#!/bin/bash
)有什么用?
shell脚本执行的方式有哪些,区别在哪里?
什么是子 Shell 和当前 Shell?
来看这两篇文章,如果你真的在好好且系统的学习shell,听话,在开始学习下面内容之前,请先阅读,我之前的文章,中国人不骗中国人
什么是位置参数变量?
位置参数变量是 Shell 中用来获取脚本运行时传入参数和状态信息的特殊变量,能够让脚本更加灵活和智能。
变量 | 含义 |
---|---|
$0 | 当前脚本的名称(包含路径) |
$1 ~ $9 | 脚本执行时传入的第 1 至第 9 个参数 |
${10} | 第 10 个及以后参数,必须用花括号包裹 |
$# | 传入参数的数量 |
$@ | 传入的所有参数,作为独立的字符串列表处理(推荐遍历参数用) |
$* | 传入的所有参数,作为一个整体字符串处理 |
$? | 上一条命令的退出状态码,0 表示成功,非 0 表示失败 |
$$ | 当前 Shell 脚本进程的 PID |
$! | 最近一次后台命令的进程号 |
$0
— 当前脚本名
$0
代表当前执行的脚本文件名,可以是绝对路径或相对路径。
问题来了?什么时候代表的绝对路径,什么时候代表的是相对路径
好~,这就需要,看你如何执行的脚本了,运行时使用的是相对路径,那么$0
就代表的是相对路径,运行时使用的是绝对路径那么代表的就是绝对路径
#!/bin/bash
echo "当前脚本名称是:$0"
还有一个问题就是:通过 source shell .sh
或者是. shell.sh
执行,则 $0
是 bash 或 -bash
;如果是软链接调用,则显示的是软链接名
来看,这也就是为什么我在写这篇文章之前,要重点写上一篇文章了
$0
是 当前 shell 进程的名称。- 当你运行一个脚本(如
bash script.sh 或 ./script.sh
),Bash 会启动一个新的子 shell 来执行这个脚本,此时$0
就是这个脚本文件名。 - 如果你使用的是
source script.sh 或 . script.sh
,不会创建新的 shell 进程,而是直接在当前 shell 中“加载”并执行该脚本。
教你几种方法,无论是使用那种方式执行脚本,都只输出脚本名称
BASH_SOURCE
变量- 它是 Bash 内置变量数组,记录了调用栈中各个脚本文件的名字。
表达式 | 含义 | 说明 |
---|---|---|
${BASH_SOURCE[0]} | 当前正在执行的脚本路径 | 最常用,用于获取自己是谁 |
${BASH_SOURCE[1]} | 调用当前脚本的上级脚本路径 | 可以用来做日志追踪、调试 |
${BASH_SOURCE[@]} | 整个调用栈数组(逐个元素) | 遍历或打印多个层级时有用 |
${BASH_SOURCE[*]} | 整个调用栈合并为一个字符串 | 方便记录日志、调试输出 |
#!/bin/bash
echo "当前脚本名称: ${BASH_SOURCE[0]}"
- basename 工具
- 是一个 标准的
Linux/Unix
命令行工具,用于:从一个文件路径中提取出“文件名”部分(即去掉目录路径)。
- 是一个 标准的
#!/bin/bash
SHELL_NAME=$(basename "$0")
echo "当前脚本名称: $SHELL_NAME"
- 还有一些标准的
Linux/Unix
命令行工具,例如 readlink 、 dirname 等。
这些命令工具大家可以下去了解一下,如果需要,我找个时间再把这些工具讲一下,评论区给我留言
$1
~ $9
— 第1到第9个参数
这些变量依次对应脚本后面传入的参数。直接讲示例
#!/bin/bash
echo "第一个参数是:$1"
echo "第二个参数是:$2"
echo "第三个参数是:$3"
${10}
、${11}
……超过9个参数
超过9个参数时,必须使用花括号,否则 $10
会被解析为 $1
+ 0
。
#!/bin/bash
echo "第十个参数是:${10}"
echo "第十一参数是:${11}"
这里有一个主意事项哦。如果你传入的第10个参数是10,执行调用
$10
也会正常的输出,这个是假象哦~,自己去琢磨一下为什么
$#
— 参数个数
这个变量表示传入脚本的参数总数。
#!/bin/bash
echo "一共传入了 $# 个参数"
$@
和 $*
的区别及用法
这两个变量都代表所有参数,但处理方式不同:
$@
:将每个参数视为独立的字符串。通常在双引号中用来遍历参数,能保持带空格参数的完整性。$*
:将所有参数当作一个整体字符串,用第一个字符(默认为空格)分隔。
注意:调用$@
和$*
的时候必须要用""
(双引号)
#!/bin/bash
echo "用 \"\$@\" 遍历参数:"
for arg in "$@"; do
echo "参数:$arg"
done
echo "用 \"\$*\" 遍历参数:"
for arg in "$*"; do
echo "参数:$arg"
done
💡 建议: 在循环遍历参数时,优先使用
"$@"
,因为它能正确处理包含空格的参数,避免错误拆分。
$?
— 上一条命令的退出状态
执行命令后,用 $?
获取其退出状态。返回值 0 表示成功,非 0 表示失败。
#!/bin/bash
ls /test
echo "命令返回状态:$?"
ls -la /data/shell
echo "命令返回状态:$?"
$$
— 当前脚本进程 PID
显示当前脚本运行的进程号,有时用于生成临时文件名等。这个在上一篇文章中已经多次运用了,可以看下
#!/bin/bash
echo "当前脚本进程号是:$$"
$!
— 最近后台命令的 PID
当脚本中执行后台任务(用 &
结尾)时,$!
会返回该后台进程号。
#!/bin/bash
sleep 60 &
echo "后台进程的 PID 是:$!"
综合示范脚本
#!/bin/bash
# 定义 ANSI 颜色代码
RED='\033[0;31m' # 红色
GREEN='\033[0;32m' # 绿色
YELLOW='\033[0;33m' # 黄色
BLUE='\033[0;34m' # 蓝色
PURPLE='\033[0;35m' # 紫色
CYAN='\033[0;36m' # 青色
NC='\033[0m' # 无颜色 (No Color)
# ===============================
# Shell 特殊变量演示脚本
# 包含 $0, $1-$9, ${10}, ${11}
# $# "$@" "$*" $? $$ $!
# ===============================
# 每个标题使用不同颜色显示
echo -e "${RED}===== 脚本执行信息 =====${NC}"
echo -e "脚本名(\$0): $0"
echo -e "${GREEN}传入参数个数(\$#): $#${NC}"
echo -e "${YELLOW}=== 参数 \$1 ~ \$9 ===${NC}"
for i in {1..9}; do
eval "val=\$$i"
echo "参数 \$${i}: ${val:-未提供}"
done
echo -e "${BLUE}=== 参数 \${10} 和 \${11} ===${NC}"
echo "第10个参数(\${10}): ${10:-未提供}"
echo "第11个参数(\${11}): ${11:-未提供}"
echo -e "${PURPLE}=== 所有参数列表(\"\$@\") ===${NC}"
index=1
for param in "$@"; do
echo "参数 \$${index}: $param"
((index++))
done
echo -e "${CYAN}=== 所有参数合并(\"\$*\") ===${NC}"
echo "\"\$*\": $*"
echo -e "${RED}=== 当前脚本进程号(\$\$) ===${NC}"
echo "当前进程 PID(\$\$): $$"
echo -e "${GREEN}=== 测试命令失败状态码(\$?) ===${NC}"
echo "尝试访问不存在的目录 /notexist:"
ls /notexist
echo "上一个命令的状态码(\$?): $?"
echo -e "${YELLOW}=== 后台执行 sleep 命令,并获取其 PID(\$!) ===${NC}"
sleep 30 &
echo "后台执行的 sleep 命令 PID 是(\$!): $!"
echo -e "${NC}\n✅ 脚本执行完毕,请注意观察不同变量的行为!"