我有一个输入文件并运行一些命令,但希望输出以与输入文件相同的名称保存。
我尝试了以下命令,但它使输出文件为空:
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
这会从尾部删除空行(除非您grep
ping 空行,否则这应该不相关)。如果这很重要,那么就在命令替换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
...最后有一堆空值。