输出保存在与输入文件名称相同的文件中

输出保存在与输入文件名称相同的文件中

我有一个输入文件并运行一些命令,但希望输出以与输入文件相同的名称保存。

我尝试了以下命令,但它使输出文件为空:

cat file1 | grep "YISHA" > file1

答案1

在 GNU 系统上,您可以使用sed(GNU 实现):

sed -i -n '/YISHA/p' file1

FreeBSD 或 OS/X 等效项:

sed -i '' -n '/YISHA/p' file1

或使用sponge来自更多实用程序:

grep "YISHA" file1 | sponge file1

答案2

删除数据时,您可以将文件写入自身并随后截断:

{
  grep YISHA
  perl -e 'truncate STDOUT, tell STDOUT'
} < file 1<> file

当然,在这里,您可以执行以下操作perl

perl -ne 'print if /YISHA/; END{truncate STDOUT, tell STDOUT}' < file 1<> file

perl还有一个-i就地编辑选项(GNUsed复制的那个):

perl -ni -e 'print if /YISHA/' file

但请注意,就像sed,它创建一个同名的新文件,它并没有真正重写该文件到位,这意味着文件的索引节点号和其他属性可能会在此过程中受到影响。它还会破坏符号链接。

答案3

您的 shell 可能会根据请求为您提供一个安全的临时文件:

grep "YISHA" <<IN > file
$(cat file)
IN

file这会从尾部删除空行(除非您grepping 空行,否则这应该不相关)。如果这很重要,那么就在命令替换echo .之后并删除最后一行。cat

您可以使用的另一个选项是dd。例如:

seq 5000000 >/tmp/temp
-rw-r--r-- 1 mikeserv mikeserv 38888896 Mar 11 04:20 /tmp/temp

只是一个足够大的虚拟文件,足以超过任何管道缓冲区。

</tmp/temp grep 5\$ |
dd bs=4k of=/tmp/temp conv=notrunc,sync

您可以看到我超出了任何可能的管道缓冲区的大小:

949+1 records in
950+0 records out
3891200 bytes (3.9 MB) copied, 0.164471 s, 23.7 MB/s

notrunc指定转换后,dd除了写入所读入的内容之外,不会触及输出文件。seek=如果您愿意,您甚至可以将该输入数据放在文件中的其他偏移量处。但是......文件仍然需要截断。您可以看到它dd也刷新了它的最后一个输入缓冲区:读入了 949+1 条记录,但写出了 950 条记录 -dd将它的最后一个输入块同步到带有空值的完整 4k 大小(当接受来自使用 stdio 的工具的管道输入时,通常可以选择合理的块大小 - 例如grep

所以...

ls -l /tmp/temp; tail /tmp/temp
-rw-r--r-- 1 mikeserv mikeserv 38888896 Mar 11 04:22 /tmp/temp

4999991
4999992
4999993
4999994
4999995
4999996
4999997
4999998
4999999
5000000

除了所写内容之外,它仍然是同一个文件dd

但...

dd if=/dev/null bs=4k seek=950 of=/tmp/temp

dd...我们可以将其截断到写入它的位置,并且...

0+0 records in
0+0 records out
0 bytes (0 B) copied, 0.000153783 s, 0.0 kB/s

……看起来好像什么也没发生,只是……

ls -l /tmp/temp; tail /tmp/temp
-rw-r--r-- 1 mikeserv mikeserv 3891200 Mar 11 04:25 /tmp/temp
4999915
4999925
4999935
4999945
4999955
4999965
4999975
4999985
4999995

dd缩短那个时间。但事实上,sync文件末尾有最后一个 ed 部分块,所以......

tail /tmp/temp | wc -c 

2383

...最后有一堆空值。

相关内容