☰
文件名里的空格与星号:引号与展开这一层
2026/9/29 11:53:39 网站建设 项目流程

授权与合规声明
本文全部操作对象均为自建隔离靶场(本机容器或隔离虚拟机),涉及安全测试的环节必须以取得合法授权为前提。未经授权的渗透测试违反《中华人民共和国网络安全法》与《刑法》相关条款,须承担相应法律责任。本文只讲环境配置、版本对照与靶场隔离,不含任何攻击步骤、利用载荷与绕过手法,请勿将文中环境指向任何非自有系统。

一、命令看到的,是一串被切好的字符串

你在靶场里下载了一份题目附件,文件名里带了一个空格。你把路径敲进命令,结果不如预期——命令像是只认了文件名的一半,另一半被当成了别的东西。同一类困惑还有两种很常见:你敲了一条带*的命令,本意是"就那一个文件",结果命令收到了一大串;你从一个变量里取路径,变量偏偏是空的,命令的表现跟上次完全不一样。

1.1 三个现象,其实在问同一个问题

这三种现象表面上看毫不相干:一个是空格,一个是星号,一个是空变量。但它们问的是同一件事——你写下的那串字符,和命令最终收到的东西,到底是不是一回事。

答案是不是。你写下的是"给 shell 看的一段文字",命令收到的是"一串已经被切好、并且可能已经被替换过的字符串"。中间隔着的那一层,就是本文要讲的参数层。

这一层的故障方式很有特点:它往往不改变命令本身的逻辑,只改变命令拿到几个字符串、每个字符串里有什么。于是现象看起来像"命令好像不太对",而不是"我写的那行字有问题"。

1.2 参数层:命令收到的是一份字符串列表

先把这一层说清楚。你在终端里敲下的一切,先交给 shell 由它解释;shell 解释完,再把结果作为若干条互相独立的字符串交给真正要执行的那个命令。命令自己从来没见过你的引号,也没见过你的*和$——它看到的只有 shell 交给它的那份字符串列表。

这就解释了很多"看起来不讲道理"的结果。命令认为参数不对,往往不是命令有毛病,而是 shell 交给它的个数和你想的不一样:你以为是一个参数、里面含着一个空格,shell 交过去的是两个参数、各自都不含空格。

所以参数层的第一句结论是:引号与展开这一层,决定的是"参数列表长什么样",而不是"命令怎么执行"。调这一层,调的是列表,不是逻辑。

1.3 本文的边界

边界说三条。第一,本文不写完整的 shell 脚本教程,不涉及变量赋值、流程控制、函数这些东西;只讲"你敲下去的这条命令,参数是怎么变成最终那个样子的"。第二,本文只讲这层机制本身,不涉及任何针对参数校验的对抗写法,也不涉及把字符串再当成代码去解释的那类用法——那是另一个话题,容易出事,本文一个字都不写。第三,本文所有命令都是无害的演示与只读查看,不改变你的靶场环境。

二、引号到底在做什么

2.1 官方给的一句话定义

Bash 官方手册在 3.1.2 Quoting 一节里,第一句话就把引号的作用说完了:

Quoting is used to remove the special meaning of certain characters or words to the shell.

翻成中文是:引用(引号)用来消除某些字符或词对 shell 的特殊含义。

这句话值得逐词读。“消除”——引号不是"添加"什么,而是减掉什么;它减掉的对象,是"对 shell 的特殊含义"。$、*、?、空格这些字符,本身在 shell 眼里都是有身份的:$意味着"后面要接一个变量",空格意味着"这里是两个词的分界",*意味着"这里要匹配一批文件名"。你把它们放进引号里,等于告诉 shell:这一段里,把它们的特殊身份收走,按普通字符处理。

一个实用推论:如果某个字符本来就没有特殊含义,给它加引号也不会出错。引号是"减"不是"加",所以"多加了引号"通常不出问题,"少加了引号"才会。

2.2 官方点名的四种引用机制

同一节里,官方列出了全部四种机制:

There are four quoting mechanisms: the escape character, single quotes, double quotes, and dollar-single quotes.

四种分别是:转义字符(反斜杠)、单引号、双引号,以及dollar-single quotes($'…'那种写法)。前三种是本文要细讲的,第四种本文只用一句带过:它属于一种"在引用内部还能表达特殊字符"的写法,日常排查参数问题时很少是核心,你只要知道官方把它单列为一种机制、不要把它和单引号混为一谈就够了。

官方把机制数说成"四种"这件事本身就有用:它意味着这四种之外的写法都不叫引用机制,不必自己再发明一套说法。

2.3 反斜杠:粒度最小的那一种

反斜杠是四种机制里粒度最小的一种,一次只作用于它后面紧挨着的那一个字符。所以它常和引号配合使用——引号管"一段",反斜杠管"一个"。

⚠️代码待验证

echo带\空格\的\名字echo"带 空格 的 名字"echo'带 空格 的 名字'

上面三条命令,最后交给echo的参数列表是同一种形状:一个参数,里面含空格。三种写法用三种机制达到了同一个目的,这正是理解引号的好入口——机制不同,目的相同:把空格的特殊含义收走。

(本文代码块均为无害演示,未在本机实际执行,也不粘贴任何运行输出;下同。)

三、单引号与双引号

3.1 单引号:连转义都无效

官方在 3.1.2.2 Single Quotes 里的原话是:

Enclosing characters in single quotes (') preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.

前半句说:把字符放在单引号里,会保留引号内每一个字符的字面值。注意措辞是"每一个字符",后面没有任何例外清单——这就是单引号最"硬"的地方:它把引号里面所有东西的特殊含义都收走了,$不展开,反斜杠也只是反斜杠。

后半句是最容易被初学者踩到的一条:单引号不可以出现在单引号之间,就算前面加了反斜杠也不行。为什么?因为反斜杠在单引号里同样失去了它的特殊含义——它已经不是"转义字符"了,只是一个普通的反斜杠字符。既然反斜杠不再能转义,单引号也就无法"逃"出去,引号只能一直延续到下一个单引号为止。

由此得到一个可以记住的结论:单引号里没有"例外",也没有"逃生舱"。需要在单引号内表达单引号本身时,做法不是加反斜杠(官方明确说不行),而是把这段引号断开、用别的机制拼起来。具体拼法本文不演示,只把"加反斜杠不行"这个结论记牢——它是单引号最反直觉的一处。

3.2 双引号里只剩四个字符还特殊

双引号的官方定义,措辞和单引号明显不同:

Enclosing characters in double quotes (") preserves the literal value of all characters within the quotes, with the exception of '$', '\', ‘\’, and, when history expansion is enabled, ‘!’.`

前半段同样是"保留字面值",但这次说的是"所有字符",后面紧跟一个with the exception of——除了四个东西:

  1. $:参数展开、命令替换、算术展开仍然会发生;
  2. 反引号:命令替换的另一种写法,仍然有效;
  3. 反斜杠:转义作用有条件地保留(下一节讲);
  4. !:在历史展开被启用的前提下,仍然特殊。

注意第四条那个限定语:“when history expansion is enabled”(当历史展开被启用时)。它不是无条件成立的——在非交互式的环境里,历史展开通常本来就不生效,!也就回到普通字符。所以"双引号里的!要不要小心"这个问题,答案是看当前这个 shell 有没有开历史展开;脱开这个前提去谈,没有意义。

双引号里想写双引号本身,用反斜杠转义——"正是那份清单里的反斜杠能够管住的对象之一。

3.3 双引号里的反斜杠,看它后面跟着谁

双引号里的反斜杠是个"部分保留"的角色。官方说它:

retains its special meaning only when followed by one of the following characters: '$', '\', ‘"’, ‘\’, or newline.`

也就是说,反斜杠只在后面紧跟这五个之一时才执行转义:$、反引号、"、\、以及换行符。后面跟的不是这几个字符时,这个反斜杠原样保留——它不会消失,也不会被当作转义。

这条的实用价值,在于解释一类"参数里多出一个反斜杠"的困惑:你在双引号里写了一个反斜杠,以为它会把后面那个字符转义掉,结果这个反斜杠自己留在了参数里。原因就是它后面跟的字符不在那五个名单内。判断它到底还算不算"转义字符",只需要看后面那一个字符是谁。

把这一章压成一张表:

你在引号里写的单引号'…'双引号"…"
$变量原样保留,不展开仍会展开
反引号原样保留仍是命令替换写法,仍有效
反斜杠只是普通字符后面跟$反引号"\换行 时转义,否则原样保留
!原样保留历史展开启用时仍特殊,否则普通字符
单引号本身不能出现,加反斜杠也不行普通字符
双引号本身普通字符用反斜杠转义
空格被保留,不再当作词的分界被保留,不再当作词的分界

四、顺序:先分词,再文件名展开

4.1 分词发生在什么阶段

参数列表在交给命令之前,会经历一串处理,其中两步最容易混淆,而且有固定先后:先做分词(word splitting),再做文件名展开(filename expansion,也就是通配符那一步)。官方在 3.5.8 Filename Expansion 的开头就把这个先后写明了:

After word splitting, unless the -f option has been set, Bash scans each word for the characters '*', '?', and '['.

第一个词就是After word splitting——在分词之后。这个先后关系直接解释了"参数个数为什么会多出来"。

顺序是这样起作用的:一段文本里既有空格又有*时,shell先按空格把它切成若干词,再对每个词单独做通配符匹配;所以结果是"每个词各自展开"后拼起来的列表,不是"整段先匹配再切开"。反过来,一段文本如果没被分词(比如整体在双引号里),它不会被切开——但通配符这一步同样不发生,因为那几个字符的特殊含义已被引号收走。

4.2 IFS 未设与设为空串,是两件事

分词到底"按什么切",由变量IFS决定。官方的说法是:shell 把$IFS的每一个字符都当作一个分隔符(不是把整个值当一个整体,而是字符逐个算)。更关键的是两种"没有值"的情况,官方把它们分得很清楚:

If IFS is unset, word splitting behaves as if its value were <space><tab><newline>...

If the value of IFS is null, no word splitting occurs.

两句放一起,差别就出来了:

  • IFS未设置(unset):分词照常进行,行为等同于它的值是空格、制表符、换行符;
  • IFS的值为空串(设了,但设成空的):完全不做分词。

这是最容易混的一对。直觉上"没设置"和"设成空的"差不多,但在分词这一层,它们的结果正好相反:前者"按默认的那几个字符去切",后者"一个都不切"。所以觉得"参数个数不对劲"时,IFS有没有被设过值得单独确认一眼——"没设"和"设空"要用两种问法去问。

4.3 没有被展开的词,不做分词

分词还有一个适用范围上的限定,官方写得很直接:

The shell scans the results of parameter expansion, command substitution, and arithmetic expansion that did not occur within double quotes for word splitting. Words that were not expanded are not split.

第一句说的是范围:shell 只去扫"参数展开、命令替换、算术展开"这三类结果,而且只扫那些没有发生在双引号里的。第二句更短,却是本章的要点:没有被展开的词,不做分词。

这句话拆开了本文开头第二个现象:你敲的*之所以能变出一串东西,不是"分词"变出来的,而是文件名展开变出来的;而那些本来就没有任何字符需要展开的部分,比如命令名本身、比如一个纯字符串参数,分词对它们没有影响。

把这一层拢一下:分词处理的只是"展开产生出来的文本";*变出文件名列表是另一步;引号的作用,是让这两步都够不着里面的字符。三条规则各管一段,混着看,就会觉得"引号怎么有时候管用有时候不管用"。

五、通配符:什么时候是模式,什么时候只是字符

5.1 未被引用才当模式

文件名展开这一步的判定标准,官方给得非常明确:

Bash scans each word for the characters '*', '?', and '['. If one of these characters appears, and is not quoted, then the word is regarded as a pattern, and replaced with a sorted list of filenames matching the pattern.

三个字符:*、?、[。判定条件是那句and is not quoted——并且它没有被引用。三个字符只要被引号收走过,特殊含义就没了,这个词也就不会被当作模式,而是原样作为一个普通字符串传下去。

还有半句容易被忽略:匹配结果会被排序之后再替换。所以展开出来的顺序不是你创建文件的顺序,而是"排过序的一批文件名"。

⚠️代码待验证

ls/tmp/靶场-*# 未被引用:星号被当成模式ls"/tmp/靶场-*"# 被双引号引用:不再是模式,按普通字符处理ls'/tmp/靶场-*'# 单引号同理

(本机未实测。三条命令的差别只在"那个星号对 shell 还算不算特殊"这一点上。)

5.2 没有匹配时,默认原样保留

通配符最反直觉的一条,是"没匹配上怎么办":

If no matching filenames are found, and the shell option nullglob is disabled, the word is left unchanged.

默认行为是:这个词原样留下来。你敲的*如果谁也没匹配到,shell 不会把它变成空,也不会中止,而是把一个字面上带星号的字符串原封不动地交给命令。很多人的困惑正来自这里——他以为参数是一个正常的文件名,其实那个参数从头到尾都带着一个星号,而它此刻就是一个普通字符。

这个默认行为是可以被开关改掉的。可以改掉它的选项有这么几个:

选项开了之后的效果
nullglob没有匹配时,这个词被移除,而不是原样保留
failglob没有匹配时让这条命令失败,命令不执行
nocaseglob匹配文件名时忽略大小写
dotglob让.开头的文件也能被通配符匹配到(见下节)

四个选项改的是不同的东西:前两个管"没匹配上怎么办",第三个管"匹配时区不区分大小写",第四个管".开头的文件算不算在匹配范围里"。它们都不影响"被引用的字符不算模式"这条基本规则——引号永远优先。

5.3 点开头的文件与 GLOBIGNORE

关于.开头的文件名,官方有一条独立规则:

When a pattern is used for filename expansion, the character '.' at the start of a filename or immediately following a slash must be matched explicitly, unless the shell option dotglob is set.

意思是:当用模式去匹配文件名时,出现在文件名开头、或者紧跟在斜杠之后的那个.,必须被显式匹配,除非开了dotglob。说人话就是:一个通配符不会顺手把点开头的文件也捞进来,你要那个点,就得自己把它写出来。这解释了"明明用了星号,点开头的文件却一个都没出现"——不是漏了,而是它们本来就不在那次匹配范围内。

还有一个用于"从结果里剔除"的机制:GLOBIGNORE。它可以把已经匹配到的某些文件名从结果里去掉。注意它的方向和前面几个选项不同:前面几个管的是"能不能匹配到",GLOBIGNORE管的是"匹配到了之后要不要留下"。

⚠️代码待验证

ls/tmp/.靶场配置# 显式写出那个点,才可能命中点开头的名字ls/tmp/*靶场配置# 星号自己不会带上点开头的名字

(本机未实测,仅作只读查看。)

文件名与引号速查卡:把单引号、双引号、反斜杠三种机制各自的"例外清单",加上分词与通配符的先后顺序,压成一页对着看。放在资料包里,扫码即可获取:

六、空参数与参数列表

6.1 显式空参数被保留,未引用空展开被移除

这一条官方同样给了两句对照:

Explicit null arguments ("") are retained and passed to commands as empty strings. Unquoted implicit null arguments, resulting from the expansion of parameters that have no values, are removed.

两句讲的是两种"空",去向完全相反:

  • 显式的空参数(你亲手写了一个""):被保留,以空字符串的身份传给命令。命令拿到的参数列表里,那个位置上确实有东西,只是它是空的。
  • 未引用的、隐式的空参数(比如一个没有值的变量被展开):被移除。那个位置什么都不剩,命令根本不知道那里原本有个占位。

这一对差别很实用。当你想"占住一个位置",就写"";当你发现"我明明写了那么多参数,命令却少收到一个",就要想一想其中是不是有一个是未引用的空展开,被悄悄拿掉了。所谓"显式"与"隐式",区别就在于那个空是不是你自己写出来的。

⚠️代码待验证

printf'[%s]\n'""$EMPTY乙# 第一个是显式空,仍在;第二个视变量而定printf'[%s]\n'甲 乙 丙# 对照:三个都非空

(本机未实测,仅演示参数个数的差别。)

6.2"$@"与$@

参数列表这一层里,最被官方点名的一对是*和@:

The special parameters '*' and '@' have special meaning when in double quotes.

注意这句话的重心:它们的"特殊含义"是在双引号里才成立的。也就是说,这两个东西一旦脱掉引号,那份"特殊含义"就无从谈起——这才是"$@"和$@差别的来源。

"$@"展开成"每个参数各自一个词",等价于把每个参数分别用引号包起来再接上,也就是"$1" "$2" …那种形状;所以参数的个数被原样保住,每个参数里的空格也各自被保住。而$@没有引号罩着,展开出来的文本还要走一遍分词——原本可能是一个带空格的参数,在分词这一步就被切成了好几个。

这就把第三章和第四章串起来了:"$@"之所以被反复推荐,是因为它同时避开了两个坑——既没有被分词切开,也没有把多个参数压成一个。
⚠️代码待验证

printf'[%s]\n'"$@"# 每个参数各自一个词,个数不变printf'[%s]\n'$@# 展开后还要分词,个数可能变

(本机未实测。这一对差别只有在参数本身含空格、或者本来为空时才看得出来。)

6.3"$*"与"$@"

"$*"和"$@"都带引号,但两者不是一回事。按官方口径,"$@"展开成"每个参数各自一个词",而"$*"展开成一个词。前者保住参数的个数,后者把全部参数压成一个。

放在命令里看,差别很直白:用"$@"参数个数与原来一致,用"$*"只收到一个参数。而"$*"和裸写的$*又不一样——后者还要再过一次分词,那就是 6.2 节讲的那件事了。

把这几小节压成一张表:

写法展开成什么参数个数
"$@"每个参数各自一个词与原来一致
$@展开后仍要分词可能变多
"$*"全部压成一个词变成一个
$*压成一个词后仍要分词可能再变

七、带走物:一页顺序表

7.1 顺序表

参数从"你写的"变成"命令收到的",中间的关键顺序是固定的。遇到"命令拿到的参数不对"时,照着这张表从上往下问:

顺序这一步做什么问自己一句
1反斜杠先收走它后面一个字符的特殊含义我的反斜杠后面跟着谁
2引号收走一段里所有字符的特殊含义这段我到底有没有引上
3参数展开把$变量变成文本(双引号内除外)变量当前是什么,是空还是没设
4对"没在双引号里"的展开结果做分词IFS是没设,还是被设成了空
5对未被引用的*?[做文件名展开有没有匹配到;没匹配到就是原样保留
6空参数去留:""留下,未引用空展开移除我是想占住位置,还是想让它消失
7把这一串字符串交给命令命令收到的个数,和我以为的一样吗

这张表最需要记住的是第 4 步在第 5 步之前:先分词,再展开文件名。顺序反了,很多现象就解释不通。

7.2 三条可带走的动作

  1. 先数参数,再研究命令。命令认为参数不对时,第一个要确认的不是命令的用法,而是"shell 交给它的到底是几个字符串"。多数时候问题在这一层。
  2. 把"没设"和"设成空"当成两个问题问。IFS如此,别的变量也如此——两者的结果常常正好相反。
  3. 无匹配的通配符不会消失,它会原样留下。看到参数里带着星号,先想想是不是这一步没匹配到。

7.3 边界与待验证

要坦白三点。第一,本文只覆盖参数层,不覆盖"命令怎么被找到"(另一层),也不覆盖"输出去了哪里"(同样是另一层);层与层之间不互相替代。第二,本文引用的 Bash 官方手册口径,截至 2026-09-27 成立,手册会继续更新,隔一段时间要自己回头核一遍。第三,有几处本文没有拿到官方逐字依据,一律标"待验证",不替它下结论。

以下几处本文只标注、不推断:不同 shell 实现(非 Bash)在某些细节上是否与 Bash 手册逐字一致,本文未逐一核验;dollar-single quotes的完整语义本文未展开,只按官方"四种机制之一"这句口径带过;以及本文全部代码块均未在本机实际执行,均为无害演示与只读查看。

参数层排查顺序卡:把 7.1 那张顺序表和三条动作抄成一页,下次遇到"命令拿到的参数不对"时按顺序走一遍。放在资料包里,扫码即可获取:

附表 A:本文引用事实与官方出处对照表

#事实(照口径,逐字原文)一手出处核验日期本文位置
1Quoting is used to remove the special meaning of certain characters or words to the shell.Bash 官方手册 3.1.2 Quoting — https://www.gnu.org/software/bash/manual/html_node/Quoting.html2026-09-27第二章
2There are four quoting mechanisms: the escape character, single quotes, double quotes, and dollar-single quotes.同第 1 行2026-09-27第二章
3Enclosing characters in single quotes (') preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.Bash 官方手册 3.1.2.2 Single Quotes — https://www.gnu.org/software/bash/manual/html_node/Single-Quotes.html2026-09-27第三章
4Enclosing characters in double quotes (") preserves the literal value of all characters within the quotes, with the exception of '$', '\', ‘\’, and, when history expansion is enabled, ‘!’.`Bash 官方手册 3.1.2.3 Double Quotes — https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html2026-09-27第三章
5双引号内反斜杠retains its special meaning only when followed by one of the following characters: '$', '\', ‘"’, ‘\’, or newline.`同第 4 行2026-09-27第三章
6The special parameters '*' and '@' have special meaning when in double quotes.同第 4 行2026-09-27第六、七章
7The shell scans the results of parameter expansion, command substitution, and arithmetic expansion that did not occur within double quotes for word splitting. Words that were not expanded are not split.Bash 官方手册 3.5.7 Word Splitting — https://www.gnu.org/software/bash/manual/html_node/Word-Splitting.html2026-09-27第四章
8The shell treats each character of $IFS as a delimiter...同第 7 行2026-09-27第四章
9If IFS is unset, word splitting behaves as if its value were <space><tab><newline>...同第 7 行2026-09-27第四章
10If the value of IFS is null, no word splitting occurs.同第 7 行2026-09-27第四章
11Explicit null arguments ("") are retained and passed to commands as empty strings. Unquoted implicit null arguments, resulting from the expansion of parameters that have no values, are removed.同第 7 行2026-09-27第六章
12After word splitting, unless the -f option has been set, Bash scans each word for the characters '*', '?', and '['. If one of these characters appears, and is not quoted, then the word is regarded as a pattern, and replaced with a sorted list of filenames matching the pattern.Bash 官方手册 3.5.8 Filename Expansion — https://www.gnu.org/software/bash/manual/html_node/Filename-Expansion.html2026-09-27第四、五章
13If no matching filenames are found, and the shell option nullglob is disabled, the word is left unchanged.(另:failglob使命令不执行,nocaseglob忽略大小写匹配)同第 12 行2026-09-27第五章
14When a pattern is used for filename expansion, the character '.' at the start of a filename or immediately following a slash must be matched explicitly, unless the shell option dotglob is set.同第 12 行2026-09-27第五章
15GLOBIGNORE可把匹配到的某些文件名从文件名展开的结果里剔除。同第 12 行2026-09-27第五章
待验证非 Bash 的其它 shell 实现,在引号与展开的细节上是否与 Bash 官方手册逐字一致——本次未逐一核验,本文不作跨实现的结论待验证项2026-09-27第三章、第七章
待验证dollar-single quotes的完整语义——本文未展开,只按官方"四种机制之一"这句口径带过待验证项2026-09-27第二章
待验证本文全部代码块均未在本机实际执行,内容为无害演示与只读查看动作,已逐块标注待验证项2026-09-27全文

说明:第 1–15 行为已核验的官方一手事实(核验日期 2026-09-27)。正文中凡出现"最新 / 目前 / 已"这类表述,一律带"截至 2026-09-27"。上述待验证项本文只标注、不给结论。

附表 B:术语速查表

术语一句话解释
参数层命令最终收到的那份字符串列表所处的层;本文只讲这一层
引用(Quoting)消除某些字符或词对 shell 的特殊含义;官方给出的机制共有四种
单引号保留引号内每一个字符的字面值;单引号本身不能出现在单引号之间,加反斜杠也不行
双引号保留几乎所有字符的字面值,例外是$、反引号、反斜杠,以及历史展开启用时的!
dollar-single quotes官方列出的第四种引用机制;本文只按这句口径带过,不展开
转义字符即反斜杠;一次只作用于它后面紧挨着的那一个字符
分词(word splitting)按$IFS的每个字符切分"展开产生的文本";未被展开的词不参与
IFS决定按什么切分的变量;未设置时按空格、制表符、换行符处理,值为空串时完全不切
文件名展开把未被引用的*?[当作模式,替换成排序后的匹配文件名列表
原样保留通配符没有匹配到文件名时的默认行为;那个词带着星号原封不动传下去
nullglob/failglob两个改变"没匹配上怎么办"的选项;前者移除该词,后者让命令失败且不执行
nocaseglob匹配文件名时忽略大小写的选项
dotglob让.开头的文件也能被通配符匹配到的选项
GLOBIGNORE把已匹配到的某些文件名从展开结果里剔除的机制
显式空参数你自己写出来的"";被保留,并以空字符串传给命令
隐式空参数未引用的空展开;被移除,那个位置什么也不剩
"$@"/"$*"前者展开成"每个参数各自一个词",后者展开成"一个词"
待验证官方没有声明、本文也未实测的命题,只标注、不下结论

写在最后:这篇用到的资料

写这篇文章时,我把 Bash 官方手册的 Quoting、Single Quotes、Double Quotes、Word Splitting、Filename Expansion 几节连起来读了一遍,最有用的一句反而是最不起眼的那半句——After word splitting。先分词、再文件名展开,顺序记牢了,很多"参数怎么多出来一个"的困惑就自己解开了。顺手也整理了几份配套的东西:

  • 文件名与引号速查卡:三种引用机制各自的例外清单,加上分词与通配符的先后顺序
  • Web 安全学习路线图:从基础打牢到安全管理,四个阶段各学什么
  • 靶场环境对照表:几个常见靶场在容器与宿主机之间的目录对应关系

资料是我自己整理的,放在下面这个码上,扫码即可获取:

添加时备注「靶场」,优先通过。

拿到之后建议先看文件名与引号速查卡那一份,下次再遇到"文件名里带空格、命令却只认了一半",先按那张顺序表走一遍,再决定从哪一步动手。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询