技术解析

cat file.txt > file.txt 导致 file.txt 被清空
0
2021-06-21 07:35:22
idczone
这个操作为什么会导致这样的结果?
cat file.txt | grep xxx | sed xxx > file.txt 也是一样
因为搜索之后无匹配内容?

因爲寫 shell (the interpreter) 的人不想 (也做不到) 幫你保護文件
熟悉命令的坑是 unix 用戶自己的責任, 詳見 unix 痛恨者指南

因为>是 bash 内部的 IO 重定向标记。当前登录的 bash 会先清空(如果是>>则不清空。)了 file.txt 然后才会 fork 出 cat grep sed 等三个进程。并根据管道符的指示把前一个命令的 stdout 重定向到后者的 stdin。最终把 sed 的 stdout 写入 file.txt 。

你这个需求还是用 sponge 吧,来自 moreutils 这个包

你这个命令有什么问题?

/>看起来有点绕
理解起来是,遇到重定向符>,会先清除重定向的目标文件,然后才执行前面的命令,然后前面的命令因为文件已经是空的,输出自然是空的?

是的。你先要求 bash 清空了文件。然后 cat 就读到空文件了。
如果你希望匹配的内容出现在原文件结尾,那么使用>>。追加写入是不会改变已有内容的。
如果你希望只出现匹配的内容,建议换下后面的文件名。

/>懂了,多谢,之前还以为是先执行前面,到重定向符才清空,所以才觉得奇怪

两个箭头表示 append,一个箭头等于 open

Stackoverflow 上有个一模一样的问题…

如果你想让上一个命令输出到 stdout 的内容 append 到一个文件,用>>

直接回答 >> 的朋友们,请注意看楼主的文件名

清空文件方法 +1

搜一下就有,不是个好问题,学习一下如何使用搜索工具吧。

cat file.txt > file.txt 肯定会让 file.txt 清空,但对于有多个管道的情况则不是“天然”会导致 file.txt 清空的(除非文档指出了一些实现细节)。
对于 cmd1 arg1 ... argn > out,shell 惟一正常的实现方式是打开 out 之后 exec,因此 out 会在 cmd1 启动之前就清空。
如果是 cmd1 args1 | cmd2 args2 > out,那么 shell 启动 cmd1、cmd2 以及打开 out 的顺序、方式可以有很多种,在文档没有规定如何实现的情况下,这可能和 shell 具体是怎么写的有关,即使确定了 shell 的实现,实际结果也可以取决于一些竞态条件的结果。

这波操作不是一条 sed -i 就搞定的么?

不是,我就是单纯的对这个重定向符为什么会这样有疑惑而已

问题 :cat file.txt | grep xxx > file.txt 会被清空
我的看法:
1shell 命令不规范,垃圾。幺蛾子。
2 在 powershell 中,用 cat file.txt | grep xxx > file.txt 也会被清空。这是因为 [最大的兼容] 。
3shell 的话,可以使用多条命令,避过这个幺蛾子。如:
a=`cat /tmp/sf.txt |grep power`
echo $a > /tmp/sf.txt

powershell 本身没有这个问题,powershell 用 get-content 打开文件,用 set-content 保存文件。
cat file.txt | grep xxx | set-content file.txt 的 cat

get-content file.txt | grep xxx | set-content file.txt
结论:
shell 命令不规范,powershell 用 [set-content] ,代替 [>] ,治疗了这个不规范。
powershell 不学 [<] ,powershell 不会 [<<] ,powershell 不懂 [EOF] ,却照样 觉得自己 很牛 x。
大家一定要记住, [<] , [>] , [<<<] , [>>] 这些 shell 中的重定向符号,是 shell 中的邪教,把人带坏,
是你成为脚本大师路上的坑。这些坑的唯一作用是“烧你脑”!


cat file.txt | grep xxx | tee file.txt
tee 命令用于写入文件,是 1974 年写出来的,Linux 和 Windows 下都有。
用>覆盖文件是因为>优先于程序执行,PowerShell 里也是这样的,这是>的本质所决定的。如果 PowerShell 发明了>,他也会做成这样。如果你不理解为什么>会优先于程序执行,需要学习一下大学操作系统课程中关于文件描述符的部分。


整串命令的执行过程是:
1. 打开输入(标准输入或者 <)。
2. 打开输出(标准输出或者 > 或者 >>)。
3. 启动程序,并把输入和输出喂给他们。
用操作系统的话来说:
open(输入) 打开输入
open(输出) 打开输出
pipe; pipe; 创建两条管道
fork 出 proc1,proc2,proc3
proc1.stdin = 输入 fd
proc1.stdout = 管道 1 入口
proc2.stdin = 管道 1 出口
proc2.stdout = 管道 2 入口
proc3.stdin = 管道 2 出口
proc3.stdout = 输出 fd
proc1/2/3 分别 exec 执行目标程序。
你的文件就是在第二步打开输出的时候被覆盖的,在三个程序还没启动的时候,输出就已经清空了。

tee 命令用于写入文件-----------这谁告诉你的?
tee 在我脑中“是把管道输入,输出到 [管道输出] ,并克隆一份,在标准输出”,即屏幕显示。
tee 一个大文件,,中文件,,,的话,因为有屏幕输出,导致这命令执行结果很慢了。
还会对用户产生 [刷屏] 攻击,捣乱屏幕输出。
结论:
把>换成 set-content,是高杆。
把>换成 tee,是幺蛾子。是从屎窝挪到尿窝。
我的格言:
win+bat 界,linux+bash 界,对待 powershell 的态度,就是脚本运维人进步的尺度。

cat file.txt >> file.txt
会提示 input file is output file

改个文件名就 vans 了。啥,你不想改名,sed -i 啊,整这么多幺蛾子

mac 上死循环,无限写文件

可以用 moreutils 里的 sponge 来解决这个问题,cat file.txt | sponge file.txt ,对实现感兴趣也可以去看看源码。

求求你,不要来这里当布道者了

这种贬低他人抬高自己的布道者是否应该封禁

The tee utility copies standard input to standard output, making a copy in zero or more files. The output is unbuffered.
求求你 RTFM 一下吧,微软员工看到都会监介的

18 楼这哥们我见过,其他群里也在那吹 powershell

直接 sed 完事了。为啥要 cat 下。。。为啥要 grep。这个是伪需求。。。

这难道不是常用的清空文件内容的方法的一种
数据地带为您的网站提供全球顶级IDC资源
在线咨询
专属客服