Shell 位置参数传递:从入门到“怀疑人生“

一、什么是位置参数

位置参数(Positional Parameters)是 Shell 脚本接收命令行输入的基础机制。当你执行 ./script.sh arg1 arg2 arg3 时,Shell 会自动将这些参数映射到一组特殊变量中:

变量 含义 示例值
$0 当前脚本名称 ./script.sh
$1 ~ $9 第 1~9 个参数 arg1, arg2
${10} 第 10 个及以后的参数 arg10
$# 参数个数(不含 $0 3
$* 所有参数,作为一个字符串 "arg1 arg2 arg3"
$@ 所有参数,作为独立字符串数组 "arg1" "arg2" "arg3"
$? 上条命令退出状态码 0(成功)
$$ 当前 Shell 进程 PID 12345

记忆技巧$## 像是在数数(count),$?? 像是在问"结果如何",$$ 两个 $ 表示"我自己的身份"。

1.1 基础用法

bash 复制代码
#!/bin/bash
echo "脚本名称: $0"
echo "第一个参数: $1"
echo "第二个参数: $2"
echo "参数总数: $#"

执行:

bash 复制代码
$ ./demo.sh hello world
echo "脚本名称: ./demo.sh"
echo "第一个参数: hello"
echo "第二个参数: world"
echo "参数总数: 2"

1.2 超过 9 个参数的陷阱

当参数超过 9 个时,必须用花括号

bash 复制代码
#!/bin/bash
echo "第10个参数: ${10}"   # ✅ 正确
echo "第10个参数: $10"     # ❌ 错误!会被解析为 $1 + "0"

执行 ./test.sh a b c d e f g h i j

  • ${10}j
  • $10a0$1 的值 a 后面拼接字符 0

二、\* 与 @ 的区别:Shell 面试的"送命题"

这是 Shell 脚本中最经典、也最容易让人困惑的知识点。两者的区别只在加引号时体现

2.1 不加引号时:行为完全相同

bash 复制代码
#!/bin/bash

echo "=== 不加引号 ==="
echo "使用 \$*:"
for arg in $*; do
    echo "  - [$arg]"
done

echo "使用 \$@:"
for arg in $@; do
    echo "  - [$arg]"
done

执行 ./test.sh "hello world" foo bar

复制代码
=== 不加引号 ===
使用 $*:
  - [hello]
  - [world]
  - [foo]
  - [bar]
使用 $@:
  - [hello]
  - [world]
  - [foo]
  - [bar]

注意 :包含空格的参数 "hello world" 被拆分成两个词!这是因为不加引号时,Shell 会对展开结果进行单词拆分(Word Splitting)

2.2 加引号时:天壤之别

bash 复制代码
#!/bin/bash

echo "=== 加引号 ==="
echo "使用 \"\$*\":"
for arg in "$*"; do
    echo "  -> [$arg]"
done

echo "使用 \"\$@\":"
for arg in "$@"; do
    echo "  -> [$arg]"
done

执行 ./test.sh "hello world" foo bar

复制代码
=== 加引号 ===
使用 "$*":
  -> [hello world foo bar]     ← 一个字符串
使用 "$@":
  -> [hello world]             ← 独立参数
  -> [foo]
  -> [bar]

2.3 区别总结

形式 展开结果 说明
$* hello world foo bar 所有参数拆分为单词
$@ hello world foo bar 所有参数拆分为单词
"$*" "hello world foo bar" 一个字符串,用 IFS 第一个字符连接
"$@" "hello world" "foo" "bar" 多个独立字符串,保留原始引号信息

最佳实践 :几乎所有情况下都应该使用 "$@",它能正确保留参数中的空格和特殊字符。


三、让人费解的案例

现在进入本文的核心------那些让人"怀疑人生"的引号与位置参数组合案例。

3.1 案例一:单引号下的 $@

bash 复制代码
#!/bin/bash

echo '不加引号: '
echo $@

echo '单引号: '
echo '$@'

echo '双引号: '
echo "$@"

执行 ./test.sh "hello world" foo

复制代码
不加引号: 
hello world foo
单引号: 
$@                           ← 字面量!
双引号: 
hello world foo

原理 :单引号(')是"强引用",会剥夺其中所有字符 的特殊含义。$@ 在单引号里不会被展开,原样输出为字面字符串 $@。双引号(")是"弱引用",允许 $ 进行参数展开。

3.2 案例二:echo '$@' | xargs 的陷阱

这是最常见的坑之一:

bash 复制代码
#!/bin/bash

# 假设我们想将所有参数通过管道传给另一个命令
# 错误写法 1:
echo '$@' | xargs echo
# 输出: $@                      ← 只传了字面量 "$@"

# 错误写法 2:
echo $@ | xargs echo
# 输出: hello world foo bar     ← 空格被拆分了,参数边界丢失

# 错误写法 3:
echo "$@" | xargs echo
# 输出: hello world foo bar     ← 所有参数合并成一个字符串

# 正确写法:
printf '%s\n' "$@" | xargs -I {} echo "处理: {}"
# 或更简单地直接传参
some_command "$@"

问题分析

  1. echo '$@' → 单引号阻止展开,管道接收到的就是两个字符 $@
  2. echo $@ → 先展开为 hello world foo bar,然后 echo 输出这个字符串,管道接收的是合并后的一个字符串
  3. echo "$@" → 展开为 hello world foo bar(一个字符串),同样丢失了参数边界
  4. printf '%s\n' "$@""$@" 展开为多个独立参数,printf 每个参数单独输出一行,管道正确传递

3.3 案例三:管道中的子 Shell 陷阱

bash 复制代码
#!/bin/bash

var="before"
echo "$var" | while read line; do
    var="after"
    echo "循环内: $var"
done
echo "循环外: $var"

输出:

复制代码
before
循环内: after
循环外: before          ← 没变!

原理 :管道符 | 会创建子 Shell(Subshell),子 Shell 中对变量的修改不会影响父 Shell。这是 Shell 中另一个让人困惑的地方,与位置参数传递密切相关。

3.4 案例四:IFS 与 "$*" 的隐藏行为

bash 复制代码
#!/bin/bash

# 默认 IFS 是 "\t\n"(空格、制表符、换行)
echo "默认 IFS:"
echo "$*"

# 修改 IFS
IFS=","
echo "修改 IFS 为逗号:"
echo "$*"

# 再改回来
IFS=" "
echo "改回空格:"
echo "$*"

执行 ./test.sh a b c

复制代码
默认 IFS:
a b c
修改 IFS 为逗号:
a,b,c
改回空格:
a b c

关键点"$*" 使用 IFS 的第一个字符作为连接符,而 "$@" 不受 IFS 影响,始终保留独立参数。

3.5 案例五:嵌套引号的"俄罗斯套娃"

bash 复制代码
#!/bin/bash

name="Alice"

# 想要输出: Alice said "hello"
echo "$name said \"hello\""    # ✅ 正确
echo '$name said "hello"'         # ❌ 输出: $name said "hello"
echo "$name said 'hello'"         # ✅ 正确
echo "$name said \'hello\'"     # ✅ 正确

# 更复杂的嵌套
cmd="echo 'hello world'"
echo "$cmd"                        # 输出: echo 'hello world'
eval "$cmd"                        # 执行: hello world

引号规则速查

  • 单引号 ':内部所有字符都是字面量,不允许嵌套单引号
  • 双引号 ":内部 $、`````、"\ 保持特殊含义
  • 单引号内不能放单引号,双引号内可以放单引号

3.6 案例六:shift 命令与位置参数

bash 复制代码
#!/bin/bash

echo "原始参数:"
echo "  \$1=$1, \$2=$2, \$3=$3, 总数=\$#=$#"

shift
echo "shift 一次后:"
echo "  \$1=$1, \$2=$2, \$3=$3, 总数=\$#=$#"

shift 2
echo "shift 两次后:"
echo "  \$1=$1, \$2=$2, 总数=\$#=$#"

执行 ./test.sh apple banana cherry date

复制代码
原始参数:
  $1=apple, $2=banana, $3=cherry, 总数=$#=4
shift 一次后:
  $1=banana, $2=cherry, $3=date, 总数=$#=3
shift 两次后:
  $1=date, $2=, 总数=$#=1

用途shift 常用于遍历所有参数,配合 while [ $# -gt 0 ] 实现命令行选项解析。

3.7 案例七:set 命令重置位置参数

bash 复制代码
#!/bin/bash

echo "原始参数: $@"

# 用 set 重置位置参数
set -- "new arg" "another one" "third"

echo "重置后参数: $@"
echo "\$1=$1, \$2=$2, \$3=$3"

输出:

复制代码
原始参数: old1 old2
重置后参数: new arg another one third
$1=new arg, $2=another one, $3=third

注意set -- 中的 -- 是必需的,防止后续参数以 - 开头时被误解析为 set 的选项。


四、位置参数传递流程

4.1 Shell 参数解析与传递全景图

#mermaid-svg-U3OzDLz8liFzO9z4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-U3OzDLz8liFzO9z4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-U3OzDLz8liFzO9z4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-U3OzDLz8liFzO9z4 .error-icon{fill:#552222;}#mermaid-svg-U3OzDLz8liFzO9z4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-U3OzDLz8liFzO9z4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-U3OzDLz8liFzO9z4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-U3OzDLz8liFzO9z4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-U3OzDLz8liFzO9z4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-U3OzDLz8liFzO9z4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-U3OzDLz8liFzO9z4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-U3OzDLz8liFzO9z4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-U3OzDLz8liFzO9z4 .marker.cross{stroke:#333333;}#mermaid-svg-U3OzDLz8liFzO9z4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-U3OzDLz8liFzO9z4 p{margin:0;}#mermaid-svg-U3OzDLz8liFzO9z4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-U3OzDLz8liFzO9z4 .cluster-label text{fill:#333;}#mermaid-svg-U3OzDLz8liFzO9z4 .cluster-label span{color:#333;}#mermaid-svg-U3OzDLz8liFzO9z4 .cluster-label span p{background-color:transparent;}#mermaid-svg-U3OzDLz8liFzO9z4 .label text,#mermaid-svg-U3OzDLz8liFzO9z4 span{fill:#333;color:#333;}#mermaid-svg-U3OzDLz8liFzO9z4 .node rect,#mermaid-svg-U3OzDLz8liFzO9z4 .node circle,#mermaid-svg-U3OzDLz8liFzO9z4 .node ellipse,#mermaid-svg-U3OzDLz8liFzO9z4 .node polygon,#mermaid-svg-U3OzDLz8liFzO9z4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-U3OzDLz8liFzO9z4 .rough-node .label text,#mermaid-svg-U3OzDLz8liFzO9z4 .node .label text,#mermaid-svg-U3OzDLz8liFzO9z4 .image-shape .label,#mermaid-svg-U3OzDLz8liFzO9z4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-U3OzDLz8liFzO9z4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-U3OzDLz8liFzO9z4 .rough-node .label,#mermaid-svg-U3OzDLz8liFzO9z4 .node .label,#mermaid-svg-U3OzDLz8liFzO9z4 .image-shape .label,#mermaid-svg-U3OzDLz8liFzO9z4 .icon-shape .label{text-align:center;}#mermaid-svg-U3OzDLz8liFzO9z4 .node.clickable{cursor:pointer;}#mermaid-svg-U3OzDLz8liFzO9z4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-U3OzDLz8liFzO9z4 .arrowheadPath{fill:#333333;}#mermaid-svg-U3OzDLz8liFzO9z4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-U3OzDLz8liFzO9z4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-U3OzDLz8liFzO9z4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-U3OzDLz8liFzO9z4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-U3OzDLz8liFzO9z4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-U3OzDLz8liFzO9z4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-U3OzDLz8liFzO9z4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-U3OzDLz8liFzO9z4 .cluster text{fill:#333;}#mermaid-svg-U3OzDLz8liFzO9z4 .cluster span{color:#333;}#mermaid-svg-U3OzDLz8liFzO9z4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-U3OzDLz8liFzO9z4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-U3OzDLz8liFzO9z4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-U3OzDLz8liFzO9z4 .icon-shape,#mermaid-svg-U3OzDLz8liFzO9z4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-U3OzDLz8liFzO9z4 .icon-shape p,#mermaid-svg-U3OzDLz8liFzO9z4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-U3OzDLz8liFzO9z4 .icon-shape .label rect,#mermaid-svg-U3OzDLz8liFzO9z4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-U3OzDLz8liFzO9z4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-U3OzDLz8liFzO9z4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-U3OzDLz8liFzO9z4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 美元星号 或 美元at
双引号加美元星号
双引号加美元at
命令行输入: 点斜杠script.sh 双引号hello world双引号 foo bar
Shell 词法分析
引号配对与识别
参数拆分
位置0 = 点斜杠script.sh
位置1 = hello world
位置2 = foo
位置3 = bar
参数个数 = 3
脚本执行
引用方式?
空格切分

hello/world/foo/bar
单个字符串

hello world foo bar
独立字符串数组

双引号hello world双引号 双引号foo双引号 双引号bar双引号
传递给命令

4.2 引号展开顺序与影响

#mermaid-svg-TnFW7ePRQGQApHYx{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TnFW7ePRQGQApHYx .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TnFW7ePRQGQApHYx .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TnFW7ePRQGQApHYx .error-icon{fill:#552222;}#mermaid-svg-TnFW7ePRQGQApHYx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TnFW7ePRQGQApHYx .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TnFW7ePRQGQApHYx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TnFW7ePRQGQApHYx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TnFW7ePRQGQApHYx .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TnFW7ePRQGQApHYx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TnFW7ePRQGQApHYx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TnFW7ePRQGQApHYx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TnFW7ePRQGQApHYx .marker.cross{stroke:#333333;}#mermaid-svg-TnFW7ePRQGQApHYx svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TnFW7ePRQGQApHYx p{margin:0;}#mermaid-svg-TnFW7ePRQGQApHYx .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-TnFW7ePRQGQApHYx .cluster-label text{fill:#333;}#mermaid-svg-TnFW7ePRQGQApHYx .cluster-label span{color:#333;}#mermaid-svg-TnFW7ePRQGQApHYx .cluster-label span p{background-color:transparent;}#mermaid-svg-TnFW7ePRQGQApHYx .label text,#mermaid-svg-TnFW7ePRQGQApHYx span{fill:#333;color:#333;}#mermaid-svg-TnFW7ePRQGQApHYx .node rect,#mermaid-svg-TnFW7ePRQGQApHYx .node circle,#mermaid-svg-TnFW7ePRQGQApHYx .node ellipse,#mermaid-svg-TnFW7ePRQGQApHYx .node polygon,#mermaid-svg-TnFW7ePRQGQApHYx .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TnFW7ePRQGQApHYx .rough-node .label text,#mermaid-svg-TnFW7ePRQGQApHYx .node .label text,#mermaid-svg-TnFW7ePRQGQApHYx .image-shape .label,#mermaid-svg-TnFW7ePRQGQApHYx .icon-shape .label{text-anchor:middle;}#mermaid-svg-TnFW7ePRQGQApHYx .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-TnFW7ePRQGQApHYx .rough-node .label,#mermaid-svg-TnFW7ePRQGQApHYx .node .label,#mermaid-svg-TnFW7ePRQGQApHYx .image-shape .label,#mermaid-svg-TnFW7ePRQGQApHYx .icon-shape .label{text-align:center;}#mermaid-svg-TnFW7ePRQGQApHYx .node.clickable{cursor:pointer;}#mermaid-svg-TnFW7ePRQGQApHYx .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-TnFW7ePRQGQApHYx .arrowheadPath{fill:#333333;}#mermaid-svg-TnFW7ePRQGQApHYx .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-TnFW7ePRQGQApHYx .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-TnFW7ePRQGQApHYx .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TnFW7ePRQGQApHYx .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-TnFW7ePRQGQApHYx .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TnFW7ePRQGQApHYx .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-TnFW7ePRQGQApHYx .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-TnFW7ePRQGQApHYx .cluster text{fill:#333;}#mermaid-svg-TnFW7ePRQGQApHYx .cluster span{color:#333;}#mermaid-svg-TnFW7ePRQGQApHYx div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-TnFW7ePRQGQApHYx .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-TnFW7ePRQGQApHYx rect.text{fill:none;stroke-width:0;}#mermaid-svg-TnFW7ePRQGQApHYx .icon-shape,#mermaid-svg-TnFW7ePRQGQApHYx .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TnFW7ePRQGQApHYx .icon-shape p,#mermaid-svg-TnFW7ePRQGQApHYx .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-TnFW7ePRQGQApHYx .icon-shape .label rect,#mermaid-svg-TnFW7ePRQGQApHYx .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TnFW7ePRQGQApHYx .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-TnFW7ePRQGQApHYx .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-TnFW7ePRQGQApHYx :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 单引号
双引号
无引号
单引号在内
双引号在内
原始命令
外层引号类型
强引用: 所有字符字面量

美元at → 字面量 美元at
弱引用: 允许美元展开

美元at → 参数展开
默认处理: 空格切分

美元at → 拆分后传递
内层引号?
单引号被双引号包裹 → 字面量

双引号内容 单引号 hi 单引号
需转义: 反斜杠双引号

双引号内容 反斜杠 hi 反斜杠
最终传递给命令

4.3 管道与子 Shell 关系图

#mermaid-svg-UgrQZzh7seZl66iQ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-UgrQZzh7seZl66iQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-UgrQZzh7seZl66iQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-UgrQZzh7seZl66iQ .error-icon{fill:#552222;}#mermaid-svg-UgrQZzh7seZl66iQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UgrQZzh7seZl66iQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-UgrQZzh7seZl66iQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UgrQZzh7seZl66iQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UgrQZzh7seZl66iQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-UgrQZzh7seZl66iQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UgrQZzh7seZl66iQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UgrQZzh7seZl66iQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UgrQZzh7seZl66iQ .marker.cross{stroke:#333333;}#mermaid-svg-UgrQZzh7seZl66iQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UgrQZzh7seZl66iQ p{margin:0;}#mermaid-svg-UgrQZzh7seZl66iQ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-UgrQZzh7seZl66iQ .cluster-label text{fill:#333;}#mermaid-svg-UgrQZzh7seZl66iQ .cluster-label span{color:#333;}#mermaid-svg-UgrQZzh7seZl66iQ .cluster-label span p{background-color:transparent;}#mermaid-svg-UgrQZzh7seZl66iQ .label text,#mermaid-svg-UgrQZzh7seZl66iQ span{fill:#333;color:#333;}#mermaid-svg-UgrQZzh7seZl66iQ .node rect,#mermaid-svg-UgrQZzh7seZl66iQ .node circle,#mermaid-svg-UgrQZzh7seZl66iQ .node ellipse,#mermaid-svg-UgrQZzh7seZl66iQ .node polygon,#mermaid-svg-UgrQZzh7seZl66iQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UgrQZzh7seZl66iQ .rough-node .label text,#mermaid-svg-UgrQZzh7seZl66iQ .node .label text,#mermaid-svg-UgrQZzh7seZl66iQ .image-shape .label,#mermaid-svg-UgrQZzh7seZl66iQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-UgrQZzh7seZl66iQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-UgrQZzh7seZl66iQ .rough-node .label,#mermaid-svg-UgrQZzh7seZl66iQ .node .label,#mermaid-svg-UgrQZzh7seZl66iQ .image-shape .label,#mermaid-svg-UgrQZzh7seZl66iQ .icon-shape .label{text-align:center;}#mermaid-svg-UgrQZzh7seZl66iQ .node.clickable{cursor:pointer;}#mermaid-svg-UgrQZzh7seZl66iQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-UgrQZzh7seZl66iQ .arrowheadPath{fill:#333333;}#mermaid-svg-UgrQZzh7seZl66iQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-UgrQZzh7seZl66iQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-UgrQZzh7seZl66iQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UgrQZzh7seZl66iQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-UgrQZzh7seZl66iQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UgrQZzh7seZl66iQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-UgrQZzh7seZl66iQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-UgrQZzh7seZl66iQ .cluster text{fill:#333;}#mermaid-svg-UgrQZzh7seZl66iQ .cluster span{color:#333;}#mermaid-svg-UgrQZzh7seZl66iQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-UgrQZzh7seZl66iQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-UgrQZzh7seZl66iQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-UgrQZzh7seZl66iQ .icon-shape,#mermaid-svg-UgrQZzh7seZl66iQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UgrQZzh7seZl66iQ .icon-shape p,#mermaid-svg-UgrQZzh7seZl66iQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-UgrQZzh7seZl66iQ .icon-shape .label rect,#mermaid-svg-UgrQZzh7seZl66iQ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UgrQZzh7seZl66iQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-UgrQZzh7seZl66iQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-UgrQZzh7seZl66iQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 子 Shell 进程 (管道创建)
父 Shell 进程
管道 |
var 仍为 before
变量 var=before
echo \@\\ 位置参数: 1, 2, 3
while read line
var=after
修改仅在子Shell生效
父Shell中 var 不变

4.4 位置参数处理决策树

#mermaid-svg-sRlnwqayF0RRjKu9{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-sRlnwqayF0RRjKu9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-sRlnwqayF0RRjKu9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-sRlnwqayF0RRjKu9 .error-icon{fill:#552222;}#mermaid-svg-sRlnwqayF0RRjKu9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sRlnwqayF0RRjKu9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-sRlnwqayF0RRjKu9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sRlnwqayF0RRjKu9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sRlnwqayF0RRjKu9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-sRlnwqayF0RRjKu9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sRlnwqayF0RRjKu9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sRlnwqayF0RRjKu9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sRlnwqayF0RRjKu9 .marker.cross{stroke:#333333;}#mermaid-svg-sRlnwqayF0RRjKu9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sRlnwqayF0RRjKu9 p{margin:0;}#mermaid-svg-sRlnwqayF0RRjKu9 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-sRlnwqayF0RRjKu9 .cluster-label text{fill:#333;}#mermaid-svg-sRlnwqayF0RRjKu9 .cluster-label span{color:#333;}#mermaid-svg-sRlnwqayF0RRjKu9 .cluster-label span p{background-color:transparent;}#mermaid-svg-sRlnwqayF0RRjKu9 .label text,#mermaid-svg-sRlnwqayF0RRjKu9 span{fill:#333;color:#333;}#mermaid-svg-sRlnwqayF0RRjKu9 .node rect,#mermaid-svg-sRlnwqayF0RRjKu9 .node circle,#mermaid-svg-sRlnwqayF0RRjKu9 .node ellipse,#mermaid-svg-sRlnwqayF0RRjKu9 .node polygon,#mermaid-svg-sRlnwqayF0RRjKu9 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-sRlnwqayF0RRjKu9 .rough-node .label text,#mermaid-svg-sRlnwqayF0RRjKu9 .node .label text,#mermaid-svg-sRlnwqayF0RRjKu9 .image-shape .label,#mermaid-svg-sRlnwqayF0RRjKu9 .icon-shape .label{text-anchor:middle;}#mermaid-svg-sRlnwqayF0RRjKu9 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-sRlnwqayF0RRjKu9 .rough-node .label,#mermaid-svg-sRlnwqayF0RRjKu9 .node .label,#mermaid-svg-sRlnwqayF0RRjKu9 .image-shape .label,#mermaid-svg-sRlnwqayF0RRjKu9 .icon-shape .label{text-align:center;}#mermaid-svg-sRlnwqayF0RRjKu9 .node.clickable{cursor:pointer;}#mermaid-svg-sRlnwqayF0RRjKu9 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-sRlnwqayF0RRjKu9 .arrowheadPath{fill:#333333;}#mermaid-svg-sRlnwqayF0RRjKu9 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-sRlnwqayF0RRjKu9 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-sRlnwqayF0RRjKu9 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sRlnwqayF0RRjKu9 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-sRlnwqayF0RRjKu9 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sRlnwqayF0RRjKu9 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-sRlnwqayF0RRjKu9 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-sRlnwqayF0RRjKu9 .cluster text{fill:#333;}#mermaid-svg-sRlnwqayF0RRjKu9 .cluster span{color:#333;}#mermaid-svg-sRlnwqayF0RRjKu9 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-sRlnwqayF0RRjKu9 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-sRlnwqayF0RRjKu9 rect.text{fill:none;stroke-width:0;}#mermaid-svg-sRlnwqayF0RRjKu9 .icon-shape,#mermaid-svg-sRlnwqayF0RRjKu9 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sRlnwqayF0RRjKu9 .icon-shape p,#mermaid-svg-sRlnwqayF0RRjKu9 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-sRlnwqayF0RRjKu9 .icon-shape .label rect,#mermaid-svg-sRlnwqayF0RRjKu9 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sRlnwqayF0RRjKu9 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-sRlnwqayF0RRjKu9 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-sRlnwqayF0RRjKu9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是





需要传递所有参数?
参数中可能包含空格?
使用 &"@\&" 需要合并为一个字符串? 使用 \&"*&"
使用 @ 或 * 均可
通过管道?
用 printf '%s

' &"@\&" \| cmd 直接 cmd \&"@&"
注意 IFS 影响连接符
注意 Word Splitting


五、最佳实践与避坑指南

5.1 黄金法则

  1. 始终使用 "$@" 传递参数

    bash 复制代码
    # ✅ 正确
    some_command "$@"
    
    # ❌ 错误
    some_command $@
    some_command $*
  2. 变量引用始终加双引号

    bash 复制代码
    # ✅ 正确
    echo "$filename"
    
    # ❌ 错误
    echo $filename
  3. 通过管道传递多参数时用 printf

    bash 复制代码
    # ✅ 正确
    printf '%s\n' "$@" | xargs -I {} process {}
    
    # ❌ 错误
    echo "$@" | xargs process
  4. 使用 shift 遍历参数

    bash 复制代码
    while [ $# -gt 0 ]; do
        echo "处理: $1"
        shift
    done
  5. 设置严格模式

    bash 复制代码
    #!/usr/bin/env bash
    set -euo pipefail

5.2 常见错误速查表

错误写法 问题 正确写法
`echo '$@' cmd` 单引号阻止展开,只传字面量 $@
`echo $@ cmd` Word Splitting 导致参数边界丢失
`echo "$@" cmd` 所有参数合并为一个字符串
$10 被解析为 $1 + 0 ${10}
for i in $*; do 空格参数被拆分 for i in "$@"; do
cmd $var 变量含空格时被拆分 cmd "$var"
set -a -b -a 被解析为选项 set -- -a -b

六、总结

Shell 位置参数的传递看似简单,实则暗藏玄机。核心要点:

  1. 单引号 vs 双引号 :单引号是"强引用",内部一切字符都是字面量;双引号是"弱引用",允许 $ 展开。echo '$@' 中的 $@ 不会被展开。

  2. "$@" 是唯一安全的全参数传递方式:它能保留每个参数的独立性和内部空格,是编写健壮脚本的基石。

  3. 管道创建子 Shell :管道符 | 右侧的命令在子 Shell 中执行,对变量的修改不会反映到父 Shell。

  4. Word Splitting 是隐形杀手:不加引号的变量展开会触发单词拆分,导致含空格的参数被撕裂。

  5. printf '%s\n' "$@" 是管道传参的标准解法 :当需要将多个参数通过管道传递时,用 printf 每个参数单独输出一行,再配合 xargs -I {}xargs -0 处理。

掌握这些规则后,那些让人"怀疑人生"的案例就不再神秘了。

相关推荐
阿图灵2 小时前
Linux常用基本命令(VI/VIM 编辑器)
linux·运维·服务器
闪电悠米2 小时前
力扣hot100-438.找到字符串中所有字母异位词-固定长度滑动窗口详解
linux·服务器·数据结构·算法·leetcode·滑动窗口·力扣hot100
风曦Kisaki12 小时前
#Linux数据库管理Day06:主从同步与MaxScale读写分离
linux·运维·数据库
小楼昨夜又东风12613 小时前
使用python快速拉包
linux
Tipriest_14 小时前
ubuntu创建和更换当前swap大小
linux·运维·ubuntu
WI8LbH78815 小时前
Ubuntu 部署Harbor
linux·运维·ubuntu
researcher-Jiang16 小时前
高性能计算之MPI:第一次MPI并行程序设计练习
linux·运维·服务器
Wireless_wifi616 小时前
Why Choose IPQ9574 for Your WiFi 7 Solution
linux·人工智能·5g
MYMOTOE616 小时前
国内对标腾讯 WorkBuddy 的桌面 AI 智能体软件大全
linux