授权与合规声明
本文全部操作对象均为自建隔离靶场(本机容器或隔离虚拟机),涉及安全测试的环节必须以取得合法授权为前提。未经授权的渗透测试违反《中华人民共和国网络安全法》与《刑法》相关条款,须承担相应法律责任。本文只讲环境配置、版本对照与靶场隔离,不含任何攻击步骤、利用载荷与绕过手法,请勿将文中环境指向任何非自有系统。
一、一个具体场景:内容到底被写进了哪个文件
1.1 三个反复出现的现象
把命令的输出存下来,这件事几乎每个初学者都做过。做法也简单:在命令后面加一个符号,再写一个文件名,回车。可做过几次之后,有三类现象会反复出现。
第一类:回头去看那个文件,它是空的。命令明明跑了,屏幕上也不是没有动静,可文件里什么都没有。
第二类:文件不是空的,但只剩下最后一小段。你以为它会从头记到尾,结果开头那部分不见了。
第三类:你想让正常输出和提示那一路都进同一个文件,写完之后打开一看,只有一半在里面——正常的那一半在,另一半不见踪影。
这三类现象看着是三件事,其实都落在同一层上:你写下的那个符号,到底把什么、送到了哪里、按什么顺序送。这一层就是重定向。它不是某个命令的功能,而是你在命令前面多写的那几个字符所决定的一层规则。
1.2 重定向不是命令的一部分,是命令执行前的动作
初学者最容易把重定向想成"命令的一个功能"。它不是。你敲下的那些符号(>、>>、<、|之类)并不交给那个命令去理解,它们是 shell 在启动命令之前先处理掉的一层记号。也就是说,命令真正跑起来的时候,它看到的世界已经被这些符号改过了:它以为自己还是照常往外写,其实那个"外面"已经被换成了你指定的文件。
这个先后关系解释了本文后面几乎全部内容。因为符号是先被处理的,"处理成什么样"就完全取决于符号本身怎么写、写在哪儿、以及写了几次。你在屏幕上看到的现象,是"命令的输出"与"shell 的改向"叠加之后的结果;分不清是哪一件造成的,就会一直在命令的参数上找原因,而问题其实在符号上。
1.3 三条规则,以及本文的边界
这一层的内容不少,但真正决定"内容被写进了哪个文件"的,只有三条规则:
- 写向哪个描述符,由符号本身决定。开头是
>的,默认指向标准输出;开头是<的,默认指向标准输入;要改就显式写出编号。 >会把它要写的那个已存在文件截断为零长度,>>不会。官方用词是 truncated to zero size——这是"文件被清空"的唯一原因。- 同一个命令里有多条重定向时,从左到右依次生效。顺序一换,落到文件里的东西就换了。
边界划在前面:本文只讲写入层——内容去哪、写的时候那个文件发生了什么。至于"命令为什么失败"“某个数字代表什么”,属于判定层的话题,本文不展开;本文也不讲怎么读系统留下的记录。本文允许的动作只有两种:演示到临时文件与只读的查看,两者都不动你自己的数据。
二、第一条规则:写向哪个描述符,由符号本身决定
2.1 官方那句话
截至 2026-09-27,Bash 官方手册在 Redirections 这一节里,先把默认值这件事讲清楚了(逐字):
if the file descriptor number is omitted, and the first character of the redirection operator is ‘<’, the redirection refers to the standard input (file descriptor 0). If the first character of the redirection operator is ‘>’, the redirection refers to the standard output (file descriptor 1).
翻成好懂的话:如果你没写描述符编号,那么 shell 就去看这个符号的第一个字符。第一个字符是<,这条重定向指的就是标准输入,也就是描述符 0;第一个字符是>,指的就是标准输出,也就是描述符 1。
“第一个字符"这四个字要圈出来。它排除了一个很自然的误读——你可能会以为"只要这个符号里有>就算指标准输出”,实际不是:判定依据只有第一个字符。后面会出现的合并写法,第一个字符就不是>,所以它走的是另一套规则,效果也跟单独的>不一样。这个伏笔在第四章会收回来。
2.2 三条默认通道
一个命令跑起来的时候,最少有三条通道是开着的:编号 0 是它读进来的地方,编号 1 是它正常写结果的地方,编号 2 是它写提示与问题的地方。平常你在屏幕上看到的内容,是 1 和 2 两路都通到同一个终端、混在一起显示的,所以你分不出哪一句来自哪一路。等你用重定向把它们分开,才第一次看清它们本来就是两条——这也是"只拿到一半"这类现象的根子:默认只动了其中一路。
| 编号 | 这条通道是干什么的 | 平常它通向哪里 |
|---|---|---|
| 0 | 命令读进来的那一路 | 你的键盘输入 |
| 1 | 命令正常写结果的那一路 | 终端 |
| 2 | 命令写提示与问题的那一路 | 终端(和 1 混在一起显示) |
三条通道里,0 是"进",1 和 2 都是"出"。
2.3 想指定哪一路,就把编号写在符号前面
默认是 0 或 1,但你可以显式指定:在符号前面写一个编号,这条重定向就作用在那一号上。官方给的一般格式里,输出那条写作[n]>[|]word,追加那条写作[n]>>word——方括号里的 n 就是描述符编号。
⚠️代码待验证
# 把正常输出送到一个临时文件(只写 /tmp 下的临时文件,不碰别的东西)echo"first line">/tmp/redirect-demo.txt# 显式写出编号 1,指向的还是同一条通道,落到的地方也一样echo"second line"1>/tmp/redirect-demo-1.txt# 想看结果就按只读方式打开这两个临时文件看一眼上面第一条没写编号,靠默认值走;第二条写了编号 1,指向同一条通道,落到的地方也一样。真正让它们不同的是"写了几次"——如果两条都用同一个文件名,第二条就会把第一条留下的内容处理掉,原因见下一章。
三、第二条规则:>会把它清空,>>不会
3.1 官方原话:truncated to zero size
这是本文最硬、也最容易吃亏的一条。官方在讲输出重定向时,把两种情况并成了一句话(逐字):
If the file does not exist it is created; if it does exist it is truncated to zero size.
中文:文件不存在就创建;文件已经存在,就把它截断为零长度。
“截断为零长度"这几个字,就是"我明明只想往里写,结果原内容没了"的唯一原因。它不是某个命令的行为,也不是某个工具的脾气,而是这个符号在打开文件的那一刻就已经按这种方式打开了:它拿到的不是"接在后面的位置”,而是"从零开始的位置"。
与此相对,追加那个符号的官方口径只说到创建(逐字):
If the file does not exist it is created.
它没有"截断"那半句。换句话说,>>打开一个已存在的文件时,不会先把它清掉,而是在原有内容的后面接着写。这一句和上一句摆在一起看,"文件被清空"这件事就有了唯一的解释。
3.2 为什么这件事特别容易发生在脚本里
在终端里手敲,你一般是知道自己在干什么的。麻烦出在把命令写进脚本之后:脚本会重复运行,第二次跑的时候那个文件已经在了,而清空那个符号又是"打开即截断",于是上一次留下的内容就这么没了。你看到的是"里面只剩这一次的",很容易以为是命令没写全,其实是文件在命令开口之前就被清成了零。
这里要说一句纪律:想保留已有内容,就用追加那个符号;只有确实想从头来过,才用清空那个符号。这条判断要在你写下符号的那一秒做完。这也是为什么同一份脚本第一次跑是对的、第二次跑就不对了——变的不是脚本,是那个文件从"不存在"变成了"已存在"。
3.3 写的时候,文件上发生了什么
把两种行为并排看,差别只有一处,后果却完全不同:
| 你用的符号 | 文件不存在时 | 文件已存在时 | 原有内容去哪了 |
|---|---|---|---|
| > | 创建 | 打开并截断为零长度 | 没有了 |
| >> | 创建 | 打开,从末尾接着写 | 还在,新内容接在后面 |
还有一种情况要单独说:如果那个文件打不开或者建不了(比如它所在的位置根本不允许你写),那么重定向本身就失败了。这时的后果是明确的:失败的重定向会让整条命令的退出状态大于零——注意,不是那个命令自己跑失败了,而是它还没开始跑,重定向这一步就没成。所以遇到"命令好像失败了,但又什么都没说"的时候,先把目光放到文件本身:它能不能被创建、能不能被写。
⚠️代码待验证
# 演示"清空"与"追加"的差别,全程只写 /tmp 下的临时文件echo"first pass">/tmp/truncate-demo.txt# 上面这一次:文件不存在则创建,已存在则截断为零长度echo"second pass">>/tmp/truncate-demo.txt# 上面这一次:不动已有内容,从末尾接着写# 想看结果就按只读方式打开这个临时文件看一眼第二次如果换成清空那个符号,文件里就只会剩第二次写进去的那一行。这正是第一章前两类现象的来源:空文件来自"清空之后什么都没写进去",只剩一小段来自"每次都被清零"。
四、第三条规则:同一个命令里,多条重定向从左到右
4.1 官方的对照例子
官方手册里有一句很短、但分量很重的话(逐字):
The order of redirections is significant.
紧接着,官方给了两条几乎一模一样、只把顺序调换了一下的命令:
⚠️代码待验证
# 官方的对照例子,这里把目标文件换成临时文件,避免写到真实工作目录ls>/tmp/dirlist2>&1ls2>&1>/tmp/dirlist两条命令的字面差异只有一处:一条是先把正常输出送进文件、再让提示那一路跟着走;另一条是先让提示那一路跟着走、再把正常输出送进文件。可官方对它们的结论完全不同:前一条把两路都送进了文件,后一条只把正常输出送进了文件。
官方给的原因也逐字写在那里(逐字):
the standard error was made a copy of the standard output before the standard output was redirected to dirlist
中文:在那条命令里,提示那一路是在正常输出被改到那个文件之前就做了"复制一份正常输出"这个动作的。于是它复制到的是"当时的正常输出",而当时那一路上还通着终端;等正常输出随后被改到文件里去,它已经复制完了,不会跟着走。
4.2 为什么我合并了,却只拿到一半
把上面这段搬回第一章的第三类现象:你想让两路都进同一个文件,写出来的顺序恰好是第二条那样的,于是文件里只有正常输出。问题不在"合并"这个动作,而在那一次复制发生在顺序的哪一步。
| 写法 | 复制发生在什么时间点 | 最后文件里有谁 |
|---|---|---|
| 先指文件,再让提示那一路跟随 | 复制发生在正常输出已经改向之后 | 两路都在 |
| 先让提示那一路跟随,再指文件 | 复制发生在正常输出改向之前 | 只有正常输出 |
这也是为什么"我把提示那一路跟着正常输出走了"这句话本身不足以说明问题——你得说清是在哪一步跟的。
4.3 合并的两种写法,以及官方推荐哪一种
既然顺序每次都要想一遍太费事,shell 就另外给了两种直接的合并写法:&>word和>&word,效果就是"两路一起",等价于"先指文件、再让提示那一路跟随"那条顺序。
官方对这两种写法还专门给了取舍(逐字):
Of the two forms, the first is preferred.
也就是两种形式里,推荐用第一种,即&>word。追加版本对应&>>word,效果等价于"先追加、再让提示那一路跟随"。
这里把第二章的伏笔收回来:&>和>之所以不是一个意思,就因为它第一个字符不是>——第一个字符不同,走的规则不同,落进文件的东西也不同。
| 你想要的 | 用推荐写法 | 它等价于哪种顺序 |
|---|---|---|
| 两路一起、覆盖写进文件 | &>word | 先指文件,再让提示那一路跟随 |
| 两路一起、追加进文件 | &>>word | 先追加,再让提示那一路跟随 |
五、把三条规则放到一起:管道与两种情况
5.1 管道默认只接标准输出
管道这个符号也属于重定向这一族。官方对它最基本的描述是:管道里每一条命令的输出,通过一根管道接到下一条命令的输入上。但默认只接**"输出"那一路**,也就是编号 1 的那一路;提示与问题那一路默认不进管道。于是你就撞上了第一章第三类现象的另一半——两条命令明明连起来了,后半段却只处理了一半内容,另一半自己跑到屏幕上去了。
想让提示那一路也一起进管道,官方给了简写(逐字):
command1’s standard error, in addition to its standard output, is connected to command2’s standard input through the pipe; it is shorthand for 2>&1 |
也就是说,这种带竖线的简写形式,把前一条命令的提示那一路连同它的正常输出一起接进管道;它本身就是2>&1 |的简写。
⚠️代码待验证
# 两种接法对照:默认只接正常输出;带简写的则两路都接进管道printf"one\n"|tra-z A-Zprintf"two\n"|&tra-z A-Z# 两条都只做文本转换,不读也不写任何真实文件5.2 有一种保护:不让清空那个符号随便覆盖
清空那个符号太好用,一不小心就把文件清空,所以 shell 备了一个开关。截至 2026-09-27,官方这一节的口径是:打开它之后,用清空那个符号去写一个已经存在的普通文件,这条重定向会失败,而不是把文件清掉。这时你还有一个带竖线的强制写法,用它明确表示"就是要覆盖"。
| 开关状态 | 用清空那个符号写已存在的普通文件 | 结果 |
|---|---|---|
| 没开 | 正常打开并截断 | 原内容被清掉,新内容写进去 |
| 开了 | 重定向不成立 | 文件保持原样,整条命令状态大于零 |
| 开了,但用带竖线的强制写法 | 明确要求覆盖 | 照常截断并写入 |
这个开关的名字与开启方式,本文不展开;你只要知道它改变的是"清空那个符号遇到已存在文件时"的行为就够了。它和第三条规则还能配合:无论开关怎么设,同一个命令里的几条重定向仍然是从左到右依次生效。
5.3 三件事要分开想
合并、管道、把输入改成文件,这三件事看着像一件,其实落在不同的位置:合并解决的是"两路进同一个文件",管道解决的是"一条命令的输出交给下一条",输入重定向解决的是"命令从哪儿读"。它们各自都受默认值影响,输出侧的默认值都是"只动正常输出那一路"。到这里,第一章那三类现象已经全部有了落点。
配套资料:把"符号—默认描述符—已存在文件时的行为"做成一张可以照抄的对照卡,放在资料包里,扫码即可获取:
六、输入侧还有两条容易被忽略的写法
6.1 here document 的结束行,要求比你想的严
输入同样可以被重定向。除了从文件读,还有一种写法是直接在命令里写一段内容,由 shell 把它当作输入送进去,这种写法一般叫 here document。
它怎么结束?官方把这条规则写得很具体(逐字):
This type of redirection instructs the shell to read input from the current source until it reads a line containing only delimiter (with no trailing blanks).
中文:shell 会一直从当前来源读下去,直到读到只包含结束标记的那一行为止。括号里那半句才是关键——结束那一行不能有多余的尾随空白。也就是说,那一行除了结束标记这几个字符,不能再多出空格或制表符;多了一个空格,它就不再是"只包含结束标记",shell 会当作普通内容继续往下读。这就是另一个高频困惑的来源:结束标记我明明写了,它却不认——问题不在标记本身,而在那一行的行尾。
还有一条和"展开"有关:如果结束标记这个词是被引用过的写法,那么这段内容不做展开,原样送进去;反之则会展开——差别就取决于你在写结束标记时有没有给它加引号。
6.2<<-会剥掉前导制表符
如果这段内容在脚本里是缩进写的,那么每一行前面都会带上缩进的空白,这会影响内容本身。为此还有一种变体写法:它会把输入行与结束行前导的制表符剥掉。注意它剥的范围很窄——只管前导的制表符;行中间的空格、以及用空格做的缩进,都不在它处理的范围里。
⚠️代码待验证
# 用 here document 把一段内容交给命令;结束标记单独一行、前后不留多余空白cat<<EOF line one line two EOF# 结束那一行必须只有结束标记本身,行尾不能多出空格或制表符6.3 here string 会补一个换行
还有一种更短的写法,一般叫 here string。它的形式是在符号后面直接跟一个词,这个词的结果会以单个字符串送进命令的标准输入,并且末尾追加一个换行。
"末尾追加一个换行"这半句,是它跟管道、跟 here document 都不太一样的地方:它不按行成批地喂,而是把整段当成一个字符串送过去,最后替你补上一个换行。所以在"最后那一行也要算作一行"的场合,它的行为和你在键盘上敲进去再回车属于同一种。
⚠️代码待验证
# here string:把一个字符串送进命令的输入,末尾会被补上一个换行tra-z A-Z<<<"hello"# 只做文本转换,不读也不写任何真实文件| 写法 | 输入从哪来 | 怎么结束 | 特别之处 |
|---|---|---|---|
| 从文件读 | 一个已存在的文件 | 读到文件末尾 | 内容完全按文件里的原样 |
| here document | 命令里写的那一段 | 单独一行的结束标记 | 结束行不能有多余尾随空白;<<-剥掉前导制表符 |
| here string | 符号后面那个词 | 不需要结束行 | 按单个字符串送,末尾补一个换行 |
七、一张对照表与本文的使用限制
7.1 从现象到动作:先问哪一条规则
| 你遇到的现象 | 先反思哪一条规则 | 要做的事 |
|---|---|---|
| 文件是空的 | 第二条 | 确认你用的是清空那个还是追加那个 |
| 只剩最后一小段 | 第二条 | 想想这个符号是不是每次都会把文件清零 |
| 合并了却只拿到一半 | 第三条 | 把两条重定向的顺序念一遍,看复制发生在哪一步 |
| 只有正常输出进了文件 | 第一条 | 默认那一号是 1,提示那一路要显式跟进来 |
| 管道后半段只处理了一半 | 第五条 | 默认只接正常输出,要一起接就用简写 |
| 结束标记没被认出来 | 第六条 | 看结束那一行的行尾有没有多余空白 |
| 重定向没成,命令却像失败了 | 第二条与第三条 | 重定向失败会让整条命令状态大于零,先查文件本身能不能写 |
这张表要从上往下读:先认出你看到的是哪一类现象,再回去对规则。
7.2 三个可以带走的习惯
- 写符号之前先问一句"我要保留原来的内容吗"。想保留就用追加那个,想从头来过才用清空那个。
- 同一行里出现两条以上重定向时,把顺序念出来。重点盯"让提示那一路跟随"这个动作,是发生在正常输出改向之前还是之后。
- 默认值先记住,再谈简写。无论合并还是管道,默认都只动正常输出那一路;先记住默认,再看简写替你把哪一路带了进来。
7.3 本文的使用限制与待验证条目
- 官方事实:本篇引用的全部官方事实,均出自 Bash 官方手册的 Redirections 与 Pipelines 两节;逐条对照与核验日期(2026-09-27)见附表 A。
- 本文的方法:把这一层归纳成三条规则的顺序、两张对照表与那三个习惯,是本文从上述官方事实里整理出来的;官方文档并没有把它们写成"这三条"。
- 待验证条目(本文未实测,不得当作结论使用):本文所有命令块均未在本机实测,只作写法演示;
noclobber打开后遇到"非普通文件"时的具体行为,官方这一节只讲了普通文件,其余情形截至 2026-09-27 本文未核到逐条依据;here string 在不同 shell 实现上是否一致,本文未实测;同一条命令在不同终端里的回显样式,本文未实测。 - 本文不给的结论:不判断你该用哪一种符号,不建议你改动任何与文件保护有关的配置,也不涉及任何非自有的环境。
配套资料:把三条规则、三类现象与两张对照表做成一份可以打印的自检页,放在资料包里,扫码即可获取:
附表 A:本文引用事实与官方出处对照表
| # | 事实(照口径) | 一手出处 | 核验日期 | 本文位置 |
|---|---|---|---|---|
| 1 | if the file descriptor number is omitted, and the first character of the redirection operator is ‘<’, the redirection refers to the standard input (file descriptor 0). If the first character of the redirection operator is ‘>’, the redirection refers to the standard output (file descriptor 1). | Bash 官方手册 3.6 Redirections:https://www.gnu.org/software/bash/manual/html_node/Redirections.html | 2026-09-27 | 第 2 章 |
| 2 | Redirecting output opens the file whose name results from the expansion of word for writing on file descriptor n | 同第 1 行 | 2026-09-27 | 第 2 章 |
| 3 | If the file does not exist it is created; if it does exist it is truncated to zero size. | 同第 1 行 | 2026-09-27 | 第 3 章 |
| 4 | If the file does not exist it is created.(追加那条只有这半句,没有 truncate) | 同第 1 行 | 2026-09-27 | 第 3 章 |
| 5 | 输出的两种通用格式分别是 `[n]>[ | ]word与[n]>>word` | 同第 1 行 | 2026-09-27 |
| 6 | The order of redirections is significant. | 同第 1 行 | 2026-09-27 | 第 4 章 |
| 7 | 官方对照例子:ls > dirlist 2>&1把两路都送进文件,ls 2>&1 > dirlist只把标准输出送进文件 | 同第 1 行 | 2026-09-27 | 第 4 章 |
| 8 | the standard error was made a copy of the standard output before the standard output was redirected to dirlist | 同第 1 行 | 2026-09-27 | 第 4 章 |
| 9 | 两种合并写法&>word与>&word;Of the two forms, the first is preferred.(追加版&>>word) | 同第 1 行 | 2026-09-27 | 第 4 章 |
| 10 | This type of redirection instructs the shell to read input from the current source until it reads a line containing only delimiter (with no trailing blanks). | 同第 1 行 | 2026-09-27 | 第 6 章 |
| 11 | here document 的 word 被引用时内容不做展开;<<-会剥掉输入行与结束行前导的制表符 | 同第 1 行 | 2026-09-27 | 第 6 章 |
| 12 | here string 的格式为[n]<<< word,word 的结果以单个字符串、末尾追加一个换行的形式送到标准输入 | 同第 1 行 | 2026-09-27 | 第 6 章 |
| 13 | noclobber(set -C)开启后用>写已存在的普通文件会重定向失败;`> | ` 可以强制写 | 同第 1 行 | 2026-09-27 |
| 14 | 打不开或建不了文件会导致重定向失败,失败的重定向会让整条命令的退出状态大于零 | 同第 1 行 | 2026-09-27 | 第 3、5、7 章 |
| 15 | The output of each command in the pipeline is connected via a pipe to the input of the next command. | Bash 官方手册 3.2.3 Pipelines:https://www.gnu.org/software/bash/manual/html_node/Pipelines.html | 2026-09-27 | 第 5 章 |
| 16 | |&形式下前一条命令的标准错误连同标准输出一起接进管道;it is shorthand for 2>&1 | | 同第 15 行 | 2026-09-27 | 第 5 章 |
说明:第 1 至 14 行出自 Bash 官方手册 Redirections 一节,照其口径引用;第 15、16 行出自同一份手册的 Pipelines 一节。英文原句一律逐字保留。凡带时间属性的表述,统一锚定为截至 2026-09-27。
附表 B:术语速查表
| 术语 | 一句话解释 |
|---|---|
| 写入层 | 本文的轴:内容被送到哪里、写的时候那个文件发生了什么 |
| 重定向 | shell 在启动命令之前先处理的一层记号,决定命令的输入输出通向何处 |
| 描述符 | 命令身上开着的通道编号;0 是进,1 是正常出,2 是提示与问题出 |
| 标准输入 | 描述符 0,命令读进来的那一路,默认接键盘 |
| 标准输出 | 描述符 1,命令正常写结果的那一路 |
| 标准错误 | 描述符 2,命令写提示与问题的那一路,默认和标准输出混在一起显示 |
| 截断为零长度 | 清空那个符号打开已存在文件时的动作,官方用词 truncated to zero size |
| 追加 | 不覆盖已有内容、从末尾接着写的写法,官方口径里只说到"不存在则创建" |
| 顺序生效 | 同一命令里多条重定向从左到右依次处理,顺序换了结果就换了 |
| 合并写法 | 把 1 与 2 一起处理的写法,推荐形式是&>word,追加版是&>>word |
| 管道 | 把前一条命令的输出接到后一条命令的输入上,默认只接标准输出 |
| here document | 直接在命令里写一段内容当作输入的写法,靠单独一行的结束标记收尾 |
| 结束标记 | 只包含它本身、不能有多余尾随空白的那一行;被引用时内容不展开 |
| 前导制表符 | 变体写法<<-会剥掉的那一段缩进;只管制表符,不管行内空格 |
| here string | 把符号后面那个词按单个字符串送进输入、末尾补一个换行的写法 |
| noclobber | 让清空那个符号不能随便覆盖已存在普通文件的开关;带竖线的写法可强制 |
| 截至 2026-09-27 | 本文对所有时间类表述的统一锚定日期 |
写在最后:这篇用到的资料
写这篇文章时,我把 Bash 官方手册里 Redirections 那一节的原文逐句读了一遍,又对着 Pipelines 那一节核了管道与简写的口径,才发现这一层真正能落成动作的东西其实只有三句话。于是顺手整理了几份配套的东西:
- 重定向对照卡:符号、默认描述符、已存在文件时的行为三栏,写命令前先扫一眼
- 靶场环境对照表:DVWA、upload-labs 在 Windows / macOS / Linux 三平台的可行性与推荐路径
- Web 安全学习路线图:从基础打牢到安全管理,四个阶段各学什么
资料是我自己整理的,放在下面这个码上,扫码即可获取:
添加时备注「靶场」,优先通过。
拿到之后建议先看重定向对照卡那一份,把自己常用的那几条命令先对着默认值过一遍,再动手装环境。