Answers:
当外壳程序获得如下命令行时:command > file.out外壳程序本身打开(并可能创建)名为的文件file.out。Shell将文件描述符0设置为它从打开处获得的文件文件描述符。这就是I / O重定向的工作方式:每个进程都知道文件描述符0、1和2。
困难的部分是如何打开file.out。在大多数情况下,您想file.out在偏移量0(即被截断)处打开以进行写入操作,这就是Shell为您完成的工作。它截断了.hgignore,将其打开以进行写入,将filedescriptor设置为0,然后执行head。即时文件破坏。
在bash shell中,执行a set noclobber更改此行为。
我认为Bruce 用Shell管道回答了这里发生的事情。
我最喜欢的小实用程序之一是moreutils的sponge命令。它通过在打开目标输出文件并写入数据之前“吸收”所有可用输入来解决此问题。它使您可以按照预期的方式编写管道:
$ head -1 .hgignore | sponge .hgignore
穷人的解决方案是将输出通过管道传输到一个临时文件,然后在完成pipline之后(例如,您运行的下一个命令)是将临时文件移回原始文件位置。
$ head -1 .hgingore > .hgignore.tmp
$ mv .hgignore{.tmp,}
head -1 .hgignore | tee .hgignore吗?tee是在coreutils中的,并且作为一种特权/副作用,这也写给STDOUT
tee与其他所有实例一样,在实例化时将打开并截断正在写入的文件,因此在用写入方式截断文件内容之前,它无法解决此处的竞争条件的主要问题。
tee 似乎可以完成所需的操作。8.13我的机器上有版本。
tee程序将截断您的文件,它没有设置为对文件进行双缓冲。
在
head -n 1 file > file
file在head开始之前被截断,但是如果您编写它:
head -n 1 file 1<> file
它不是以file读写模式打开的。但是,head完成写入后,它不会截断文件,因此,上面的行是空操作(head只会将第一行重写为自身,而其他行则保持不变)。
但是,在head返回之后并且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
STDIN类似于您在perl上面使用的命令所截断的内容吗
dd可以在文件中的任意绝对偏移处截断。所以,你可以确定字节与第二线并截断的偏移,从那里dd bs=1 seek="$offset" of=file
真正的男人的解决方案是
ed .hgignore
$d
wq
或单线
printf '%s\n' '$d' 'wq' | ed .hgignore
或使用GNU sed:
sed -i '$d' .hgignore
(不,我在开玩笑。我会使用交互式编辑器。vi .hgignore GddZZ)
:wqover 有什么优势ZZ吗?
:x这就是我的手指自动执行的操作
ZQ与:q!
对于就地文件编辑,您还可以使用打开文件处理技巧,如JürgenHötzel在sed's / c / d /'myFile到myFile的重定向输出中所示。
exec 3<.hgignore
rm .hgignore # prevent open file from being truncated
head -1 <&3 > .hgignore
ls -l .hgignore # note that permissions may have changed
rm .hgignore您的电源故障之后,就可以节省数小时的辛苦工作。好的,这并不重要.hgignore,但是为什么您仍然要做一些复杂的事情?因此,我的反对意见是:技术上正确,但非常糟糕的主意。
perl -i(用于就地编辑)的功能,如果它的某些实现sed -i也做到这一点,我不会感到惊讶(尽管最新版本的GNU sed似乎没有)。
cut在原位置更改文件吗?,如何使iconv用转换后的输出替换输入文件?