今天我试图.hgignore
从 Cygwin bash shell 快速编辑一个文件,但我添加了一行错误的内容。我不确定这是否是最好的方法,但我很快想到使用head -1 .hgignore
删除有问题的行(我以前在文件中只有一行)。果然,执行时它给出第一行作为唯一的输出。
但是当我尝试重定向输出并使用 重写文件时head -1 .hgignore > .hgignore
,该文件是空的。为什么会出现这种情况?如果我尝试附加,head -1 .hgignore >> .hgignore
它会正确附加,但这显然不是所需的结果。为什么截断重定向在这种情况下不起作用?
答案1
答案2
当 shell 获取如下命令行时:command > file.out
shell 本身会打开(并且可能创建)名为file.out
. shell 将文件描述符 0 设置为它从 open 获得的文件描述符。这就是 I/O 重定向的工作原理:每个进程都知道文件描述符 0、1 和 2。
最困难的部分是如何打开file.out
。大多数时候,您希望file.out
在偏移量 0 处打开写入(即截断),这就是 shell 为您所做的。它截断了 .hgignore,打开它进行写入,将文件描述符复制为 0,然后执行 exec head
。即时文件破坏。
在 bash shell 中,您可以执行 aset noclobber
来更改此行为。
答案3
在
head -n 1 file > file
file
head
在开始之前被截断,但是如果你写它:
head -n 1 file 1<> file
它不是file
以读写模式打开的。但是,当head
完成写入时,它不会截断文件,因此上面的行将是无操作(head
只会重写第一行本身并保持其他行不变)。
但是, afterhead
返回后,当fd
仍然打开时,您可以调用另一个执行truncate
.
例如:
{ head -n 1 file; perl -e 'truncate STDOUT, tell STDOUT'; } 1<> file
这里重要的是truncate
,上面的内容head
只是将光标移动到文件内第一行之后的 fd 1 处。它确实重写了我们不需要的第一行,但这没有害处。
有了 POSIX 头,我们实际上可以不用重写第一行就可以逃脱:
{ head -n 1 > /dev/null
perl -e 'truncate STDIN, tell STDIN'
} <> file
head
在这里,我们使用在标准输入中移动光标位置的事实。虽然head
通常会通过大块读取输入来提高性能,但 POSIX 会要求它(如果可能)seek
在第一行超出时立即返回。但请注意,并非所有实现都这样做。
read
或者,在这种情况下,您可以使用 shell 的命令:
{ read -r dummy; perl -e 'truncate STDIN, tell STDIN'; } <> file
答案4
您可以在 Ex 模式下使用 Vim:
ex -sc '2,d|x' .hgignore
2,
选择第 2 行直到末尾d
删除x
保存并关闭