cat file.txt > file.txt 导致 file.txt 被清空

2019-06-10 22:01:56 +08:00
 HeiXiaoBai
这个操作为什么会导致这样的结果?
cat file.txt | grep xxx | sed xxx > file.txt 也是一样
7405 次点击
所在节点    Linux
40 条回复
ps1aniuge
2019-06-11 11:08:32 +08:00
tee 命令用于写入文件-----------这谁告诉你的?
tee 在我脑中“是把管道输入,输出到 [管道输出] ,并克隆一份,在标准输出”,即屏幕显示。

tee 一个大文件,,中文件,,,的话,因为有屏幕输出,导致这命令执行结果很慢了。
还会对用户产生 [刷屏] 攻击,捣乱屏幕输出。

结论:
把>换成 set-content,是高杆。
把>换成 tee,是幺蛾子。是从屎窝挪到尿窝。

我的格言:
win+bat 界,linux+bash 界,对待 powershell 的态度,就是脚本运维人进步的尺度。
hjq98765
2019-06-11 11:37:21 +08:00
cat file.txt >> file.txt

会提示 input file is output file
guog
2019-06-11 12:01:59 +08:00
@ps1aniuge #21 改个文件名就 vans 了。啥,你不想改名,sed -i 啊,整这么多幺蛾子
guog
2019-06-11 12:04:30 +08:00
@hjq98765 #22 mac 上死循环,无限写文件
PTLin
2019-06-11 12:36:18 +08:00
可以用 moreutils 里的 sponge 来解决这个问题,cat file.txt | sponge file.txt ,对实现感兴趣也可以去看看源码。
masker
2019-06-11 13:12:37 +08:00
@ps1aniuge 求求你,不要来这里当布道者了
masker
2019-06-11 13:14:06 +08:00
@livid #18 这种贬低他人抬高自己的布道者是否应该封禁
momocraft
2019-06-11 13:15:12 +08:00
The tee utility copies standard input to standard output, making a copy in zero or more files. The output is unbuffered.

求求你 RTFM 一下吧,微软员工看到都会监介的
guanzhangzhang
2019-06-11 13:16:56 +08:00
@masker 18 楼这哥们我见过,其他群里也在那吹 powershell
catcalse
2019-06-11 14:49:57 +08:00
直接 sed 完事了。为啥要 cat 下。。。为啥要 grep。这个是伪需求。。。
newmind
2019-06-11 18:10:34 +08:00
这难道不是常用的清空文件内容的方法的一种😄
snoopygao
2019-06-11 20:07:58 +08:00
这命令让我想起了人体蜈蚣
msg7086
2019-06-11 22:57:00 +08:00
@guog @masker 之前我还在犹豫要不要 block,现在发现无需犹豫了~ 顺便 @Livid 一下。
scriptB0y
2019-06-11 23:42:59 +08:00
@msg7086 说的这个过程,其实楼主可以用 strace 自己验证一下

strace -f sh -c "cat file.txt | grep xxx | sed xxx > file.txt " 可以看到整个过程的。
siteshen
2019-06-11 23:57:01 +08:00
本来用例 1 想质疑 #3 @vuuv 的答案,然而重读一遍后,又用例 2 推翻了我的质疑。

cat hello.txt | grep a | (sleep 1; cat > hello.txt) # 例 1:文件不会被清空
cat hello.txt | (sleep 1; grep a) | cat > hello.txt # 例 2:文件会被清空
FrankHB
2019-06-12 00:05:46 +08:00
@ps1aniuge
你似乎不知道啥叫“规范”。
POSIX shell 是屑,bash 有 private extensions,不妨碍 POSIX 标准化了带有 I/O redirection 的 shell command language。
相比之下,ps1 的设计好上那么一丢丢,也改不掉 M$的写 spec 落后的现状。ECMA-262 还落后 VC#几年呢……你指望 ps1 能规范就猴年马月了。
另外,所谓屏幕输出也是你自以为是的笑话,尽管偶然符合事实。tee 命令操作的是标准输入和标准输出。在 UNIX 的万物皆文件的邪教下,对应文件还真没错。下面那个叫你 RTFM 的咣的还真是时候。
另外你漏了 POSIX.1 标准化的 tee 命令还有一个破事:禁止忽略错误。
FrankHB
2019-06-12 00:06:30 +08:00
ok,婊 js 魔怔了,262→334 ……
vuuv
2019-06-12 14:54:36 +08:00
@siteshen #35 文件真的没有被清空吗?看下文件的修改时间?
你写的的 hello.txt 是不是每行都恰好包含字母 a 呢?加一行不含字母 a 的内容试试?

例 1 里的圆括号“()”标记会 fork 一个 shell (暂称为子 shell )来执行。于是命令等价为这样的:
cat hello.txt | grep a | bash -c "sleep 1; cat > hello.txt"

如果没有 sleep 1,那么会立刻在子 shell 里发生文件清空。不过此时 cat 和子 shell 是同时 fork 的,而且子 shell 启动后的初始化及对命令的语法解析会花费一些时间(也就几十毫秒而已)。
如果 hello.txt 文件较小,等到子 shell 开始奉命清空文件时,cat 是有充足的时间读到文件全部内容的。如果文件超出了缓冲区大小(缓冲区默认是 4k,不过程序可以设置其他大小,内核也可能会多预读点内容。),就不保证 cat 能读到正确的内容了。

所以一些软件系统会设计为“对关键文件的修改加锁”,就是为了防止多个进程同时修改某个文件。
典型的代表就是 yum 的 install 子命令。
ps1aniuge
2019-06-12 17:26:20 +08:00
@masker
v2 是高智商、程序员的技术社区。
而你这智商,明显差强任意。拉低了社区平均值。

什么贬低他人 ? “他人”是指谁? 技术和人你都分不清楚么?
james122333
2019-06-13 10:01:40 +08:00
pipe 能实现的 导向都能实现 多写就了解了
这需求 shell 完全能实现 据我看到的所有写 pipe 一行流的大型应用都写的很丑 举例:steam 的启动脚本
shell 是能写的优雅好维护的 精随少人在讲而已...

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/572624

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX