ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

内容被写进了哪个文件:重定向这一层的三条规则

内容被写进了哪个文件:重定向这一层的三条规则 授权与合规声明本文全部操作对象均为自建隔离靶场本机容器或隔离虚拟机涉及安全测试的环节必须以取得合法授权为前提。未经授权的渗透测试违反《中华人民共和国网络安全法》与《刑法》相关条款须承担相应法律责任。本文只讲环境配置、版本对照与靶场隔离不含任何攻击步骤、利用载荷与绕过手法请勿将文中环境指向任何非自有系统。一、一个具体场景内容到底被写进了哪个文件1.1 三个反复出现的现象把命令的输出存下来这件事几乎每个初学者都做过。做法也简单在命令后面加一个符号再写一个文件名回车。可做过几次之后有三类现象会反复出现。第一类回头去看那个文件它是空的。命令明明跑了屏幕上也不是没有动静可文件里什么都没有。第二类文件不是空的但只剩下最后一小段。你以为它会从头记到尾结果开头那部分不见了。第三类你想让正常输出和提示那一路都进同一个文件写完之后打开一看只有一半在里面——正常的那一半在另一半不见踪影。这三类现象看着是三件事其实都落在同一层上你写下的那个符号到底把什么、送到了哪里、按什么顺序送。这一层就是重定向。它不是某个命令的功能而是你在命令前面多写的那几个字符所决定的一层规则。1.2 重定向不是命令的一部分是命令执行前的动作初学者最容易把重定向想成命令的一个功能。它不是。你敲下的那些符号、、、|之类并不交给那个命令去理解它们是 shell 在启动命令之前先处理掉的一层记号。也就是说命令真正跑起来的时候它看到的世界已经被这些符号改过了它以为自己还是照常往外写其实那个外面已经被换成了你指定的文件。这个先后关系解释了本文后面几乎全部内容。因为符号是先被处理的处理成什么样就完全取决于符号本身怎么写、写在哪儿、以及写了几次。你在屏幕上看到的现象是命令的输出与shell 的改向叠加之后的结果分不清是哪一件造成的就会一直在命令的参数上找原因而问题其实在符号上。1.3 三条规则以及本文的边界这一层的内容不少但真正决定内容被写进了哪个文件的只有三条规则写向哪个描述符由符号本身决定。开头是的默认指向标准输出开头是的默认指向标准输入要改就显式写出编号。会把它要写的那个已存在文件截断为零长度不会。官方用词是 truncated to zero size——这是文件被清空的唯一原因。同一个命令里有多条重定向时从左到右依次生效。顺序一换落到文件里的东西就换了。边界划在前面本文只讲写入层——内容去哪、写的时候那个文件发生了什么。至于命令为什么失败“某个数字代表什么”属于判定层的话题本文不展开本文也不讲怎么读系统留下的记录。本文允许的动作只有两种演示到临时文件与只读的查看两者都不动你自己的数据。二、第一条规则写向哪个描述符由符号本身决定2.1 官方那句话截至 2026-09-27Bash 官方手册在 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 下的临时文件不碰别的东西echofirst line/tmp/redirect-demo.txt# 显式写出编号 1指向的还是同一条通道落到的地方也一样echosecond line1/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 下的临时文件echofirst pass/tmp/truncate-demo.txt# 上面这一次文件不存在则创建已存在则截断为零长度echosecond pass/tmp/truncate-demo.txt# 上面这一次不动已有内容从末尾接着写# 想看结果就按只读方式打开这个临时文件看一眼第二次如果换成清空那个符号文件里就只会剩第二次写进去的那一行。这正是第一章前两类现象的来源空文件来自清空之后什么都没写进去只剩一小段来自每次都被清零。四、第三条规则同一个命令里多条重定向从左到右4.1 官方的对照例子官方手册里有一句很短、但分量很重的话逐字The order of redirections is significant.紧接着官方给了两条几乎一模一样、只把顺序调换了一下的命令⚠️代码待验证# 官方的对照例子这里把目标文件换成临时文件避免写到真实工作目录ls/tmp/dirlist21ls21/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 21 |也就是说这种带竖线的简写形式把前一条命令的提示那一路连同它的正常输出一起接进管道它本身就是21 |的简写。⚠️代码待验证# 两种接法对照默认只接正常输出带简写的则两路都接进管道printfone\n|tra-z A-Zprintftwo\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 把一段内容交给命令结束标记单独一行、前后不留多余空白catEOF line one line two EOF# 结束那一行必须只有结束标记本身行尾不能多出空格或制表符6.3 here string 会补一个换行还有一种更短的写法一般叫 here string。它的形式是在符号后面直接跟一个词这个词的结果会以单个字符串送进命令的标准输入并且末尾追加一个换行。末尾追加一个换行这半句是它跟管道、跟 here document 都不太一样的地方它不按行成批地喂而是把整段当成一个字符串送过去最后替你补上一个换行。所以在最后那一行也要算作一行的场合它的行为和你在键盘上敲进去再回车属于同一种。⚠️代码待验证# here string把一个字符串送进命令的输入末尾会被补上一个换行tra-z A-Zhello# 只做文本转换不读也不写任何真实文件写法输入从哪来怎么结束特别之处从文件读一个已存在的文件读到文件末尾内容完全按文件里的原样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本文引用事实与官方出处对照表#事实照口径一手出处核验日期本文位置1if 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 Redirectionshttps://www.gnu.org/software/bash/manual/html_node/Redirections.html2026-09-27第 2 章2Redirecting output opens the file whose name results from the expansion of word for writing on file descriptor n同第 1 行2026-09-27第 2 章3If the file does not exist it is created; if it does exist it is truncated to zero size.同第 1 行2026-09-27第 3 章4If the file does not exist it is created.追加那条只有这半句没有 truncate同第 1 行2026-09-27第 3 章5输出的两种通用格式分别是 [n][]word与[n]word同第 1 行2026-09-276The order of redirections is significant.同第 1 行2026-09-27第 4 章7官方对照例子ls dirlist 21把两路都送进文件ls 21 dirlist只把标准输出送进文件同第 1 行2026-09-27第 4 章8the 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与wordOf the two forms, the first is preferred.追加版word同第 1 行2026-09-27第 4 章10This 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 章11here document 的 word 被引用时内容不做展开-会剥掉输入行与结束行前导的制表符同第 1 行2026-09-27第 6 章12here string 的格式为[n] wordword 的结果以单个字符串、末尾追加一个换行的形式送到标准输入同第 1 行2026-09-27第 6 章13noclobberset -C开启后用写已存在的普通文件会重定向失败 可以强制写同第 1 行2026-09-2714打不开或建不了文件会导致重定向失败失败的重定向会让整条命令的退出状态大于零同第 1 行2026-09-27第 3、5、7 章15The output of each command in the pipeline is connected via a pipe to the input of the next command.Bash 官方手册 3.2.3 Pipelineshttps://www.gnu.org/software/bash/manual/html_node/Pipelines.html2026-09-27第 5 章16|形式下前一条命令的标准错误连同标准输出一起接进管道it is shorthand for 21 |同第 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 安全学习路线图从基础打牢到安全管理四个阶段各学什么资料是我自己整理的放在下面这个码上扫码即可获取添加时备注「靶场」优先通过。拿到之后建议先看重定向对照卡那一份把自己常用的那几条命令先对着默认值过一遍再动手装环境。
返回列表