1
Jirajine 2019-06-10 22:07:13 +08:00 via Android
因为搜索之后无匹配内容?
|
2
momocraft 2019-06-10 22:07:30 +08:00 1
因爲寫 shell (the interpreter) 的人不想 (也做不到) 幫你保護文件
熟悉命令的坑是 unix 用戶自己的責任, 詳見 unix 痛恨者指南 |
3
vuuv 2019-06-10 22:08:43 +08:00 via Android 18
因为>是 bash 内部的 IO 重定向标记。当前登录的 bash 会先清空(如果是>>则不清空。)了 file.txt 然后才会 fork 出 cat grep sed 等三个进程。并根据管道符的指示把前一个命令的 stdout 重定向到后者的 stdin。最终把 sed 的 stdout 写入 file.txt 。
|
4
ericFork 2019-06-10 22:12:23 +08:00
你这个需求还是用 sponge 吧,来自 moreutils 这个包
|
5
kwlokip 2019-06-10 22:14:25 +08:00 via Android
你这个命令有什么问题?
|
6
HeiXiaoBai OP |
7
vuuv 2019-06-10 22:19:57 +08:00 via Android 1
@HeiXiaoBai #6 是的。你先要求 bash 清空了文件。然后 cat 就读到空文件了。
如果你希望匹配的内容出现在原文件结尾,那么使用>>。追加写入是不会改变已有内容的。 如果你希望只出现匹配的内容,建议换下后面的文件名。 |
8
HeiXiaoBai OP @vuuv #7
懂了,多谢,之前还以为是先执行前面,到重定向符才清空,所以才觉得奇怪 |
9
pkookp8 2019-06-10 22:53:44 +08:00 via Android
两个箭头表示 append,一个箭头等于 open
|
10
Meltdown 2019-06-10 22:54:33 +08:00 via Android 1
Stackoverflow 上有个一模一样的问题…
|
11
Hardrain 2019-06-11 00:05:34 +08:00
如果你想让上一个命令输出到 stdout 的内容 append 到一个文件,用>>
|
12
also24 2019-06-11 00:12:35 +08:00
直接回答 >> 的朋友们,请注意看楼主的文件名
|
13
ADMlN 2019-06-11 00:23:16 +08:00
清空文件方法 +1
|
14
CEBBCAT 2019-06-11 01:19:52 +08:00 via Android
搜一下就有,不是个好问题,学习一下如何使用搜索工具吧。
|
15
geelaw 2019-06-11 05:33:34 +08:00 via iPhone
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 的实现,实际结果也可以取决于一些竞态条件的结果。 |
16
yejianmail 2019-06-11 08:54:14 +08:00 via Android
这波操作不是一条 sed -i 就搞定的么?
|
17
HeiXiaoBai OP @yejianmail 不是,我就是单纯的对这个重定向符为什么会这样有疑惑而已
|
18
ps1aniuge 2019-06-11 10:42:08 +08:00
问题 :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 #linux 的 cat 或 get-content file.txt | grep xxx | set-content file.txt 结论: shell 命令不规范,powershell 用 [set-content] ,代替 [>] ,治疗了这个不规范。 powershell 不学 [<] ,powershell 不会 [<<] ,powershell 不懂 [EOF] ,却照样 觉得自己 很牛 x。 大家一定要记住, [<] , [>] , [<<<] , [>>] 这些 shell 中的重定向符号,是 shell 中的邪教,把人带坏, 是你成为脚本大师路上的坑。这些坑的唯一作用是“烧你脑”! |
19
msg7086 2019-06-11 10:47:53 +08:00 2
@ps1aniuge
cat file.txt | grep xxx | tee file.txt tee 命令用于写入文件,是 1974 年写出来的,Linux 和 Windows 下都有。 用>覆盖文件是因为>优先于程序执行,PowerShell 里也是这样的,这是>的本质所决定的。如果 PowerShell 发明了>,他也会做成这样。如果你不理解为什么>会优先于程序执行,需要学习一下大学操作系统课程中关于文件描述符的部分。 |
20
msg7086 2019-06-11 10:56:01 +08:00 5
@HeiXiaoBai
整串命令的执行过程是: 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 执行目标程序。 你的文件就是在第二步打开输出的时候被覆盖的,在三个程序还没启动的时候,输出就已经清空了。 |
21
ps1aniuge 2019-06-11 11:08:32 +08:00
tee 命令用于写入文件-----------这谁告诉你的?
tee 在我脑中“是把管道输入,输出到 [管道输出] ,并克隆一份,在标准输出”,即屏幕显示。 tee 一个大文件,,中文件,,,的话,因为有屏幕输出,导致这命令执行结果很慢了。 还会对用户产生 [刷屏] 攻击,捣乱屏幕输出。 结论: 把>换成 set-content,是高杆。 把>换成 tee,是幺蛾子。是从屎窝挪到尿窝。 我的格言: win+bat 界,linux+bash 界,对待 powershell 的态度,就是脚本运维人进步的尺度。 |
22
hjq98765 2019-06-11 11:37:21 +08:00
cat file.txt >> file.txt
会提示 input file is output file |
25
PTLin 2019-06-11 12:36:18 +08:00
可以用 moreutils 里的 sponge 来解决这个问题,cat file.txt | sponge file.txt ,对实现感兴趣也可以去看看源码。
|
28
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 一下吧,微软员工看到都会监介的 |
29
guanzhangzhang 2019-06-11 13:16:56 +08:00
@masker 18 楼这哥们我见过,其他群里也在那吹 powershell
|
30
catcalse 2019-06-11 14:49:57 +08:00
直接 sed 完事了。为啥要 cat 下。。。为啥要 grep。这个是伪需求。。。
|
31
newmind 2019-06-11 18:10:34 +08:00 via Android
这难道不是常用的清空文件内容的方法的一种😄
|
32
snoopygao 2019-06-11 20:07:58 +08:00
这命令让我想起了人体蜈蚣
|
34
scriptB0y 2019-06-11 23:42:59 +08:00
@msg7086 说的这个过程,其实楼主可以用 strace 自己验证一下
strace -f sh -c "cat file.txt | grep xxx | sed xxx > file.txt " 可以看到整个过程的。 |
35
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:文件会被清空 |
36
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 命令还有一个破事:禁止忽略错误。 |
37
FrankHB 2019-06-12 00:06:30 +08:00
ok,婊 js 魔怔了,262→334 ……
|
38
vuuv 2019-06-12 14:54:36 +08:00 via Android
@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 子命令。 |
39
ps1aniuge 2019-06-12 17:26:20 +08:00
|
40
james122333 2019-06-13 10:01:40 +08:00
pipe 能实现的 导向都能实现 多写就了解了
这需求 shell 完全能实现 据我看到的所有写 pipe 一行流的大型应用都写的很丑 举例:steam 的启动脚本 shell 是能写的优雅好维护的 精随少人在讲而已... |