我想知道是否有办法在bash中的某个文本文件行之后删除所有内容。所以说有一个10行的文本文件,我想删除第4行之后的每一行,所以只剩下前4行,我该怎么做呢?
答案 0 :(得分:2)
您可以使用GNU sed
:
sed -i '5,$d' file.txt
也就是说,5,$
表示范围行5直到结束,d
表示删除。
只剩下前4行。
-i
标志告诉sed
就地编辑文件。
如果您只有BSD sed
,则-i
标志需要备份文件后缀:
sed -i.bak '5,$d' file.txt
正如@ephemient指出的那样,虽然这个解决方案很简单,
这是低效的,因为sed
仍然会在文件结尾之前读取输入,这是不必要的。
正如@agc指出的那样,我的第一个提案的反逻辑实际上可能更直观。也就是说,不要默认打印(-n
标志),
并明确打印范围1,4
:
sed -ni.bak 1,4p file.txt
另一个简单的替代方案,假设前4行不会过长,因此它们很容易适合内存,并且假设第4行以换行符结尾, 你可以将前4行读入内存,然后覆盖文件:
lines=$(head -n 4 file.txt)
echo "$lines" > file.txt
答案 1 :(得分:2)
sed
方法@janos简单但效率低下。它将读取原始文件中的每一行,即使它可以忽略的行(虽然可以使用4q
修复),-i
实际创建一个新文件(它重命名以替换原始文件) 。还有一个烦人的地方你需要使用sed -i '5,$d' file.txt
和GNU sed,sed -i '' '5,$d' file.txt
和BSD sed,以便删除现有文件而不是留下备份。
执行较少I / O的另一种方法:
dd bs=1 count=0 if=/dev/null of=file.txt \
seek=$(grep -b ^ file.txt | tail -n+5 | head -n1 | cut -d: -f1)
grep -b ^ file.txt
打印出每行的字节偏移量,例如
$ yes | grep -b ^
0:y
2:y
4:y
...
tail -n+5
跳过前4行,输出5 th 和后续行
head -n1
只接受下一行(例如只有5 th 行)
head
读取一行后,它将退出。这会导致tail
退出,因为它无处可输出。这导致grep
出于同样的原因退出。因此,file.txt
的其余部分不需要进行检查。
cut -d: -f1
仅占用:
之前的第一部分(字节偏移量)
dd bs=1 count=0 if=/dev/null of=file.txt seek=N
使用1字节的块大小,设法阻止N
的<{1}}
从file.txt
复制0个大小为1个字节的块到/dev/null
在此截断file.txt
(因为未提供file.txt
)
简而言之,这将删除{<1>}的5 th 和后续行中的所有数据。
在Linux上有一个名为conv=notrunc
的命令,可以类似地扩展或截断文件,但这不是可移植的。
UNIX文件系统支持有效截断文件,这些命令是可移植的。缺点是写出更多的工作。
(另外,file.txt
会向stderr打印一些不必要的统计信息,如果文件少于5行,则会以错误退出,但在这种情况下,它会保留现有文件内容,因此行为仍然是正确的。如果需要,也可以解决这些问题。)
答案 2 :(得分:1)
答案 3 :(得分:0)
使用GNU awk(v.4.1.0 +,见here)。首先,我们创建一个测试文件(注意免责声明):
$ seq 1 10 > file # THIS WILL OVERWRITE FILE NAMED file WITH TEST DATA
然后代码和验证(将修改原始文件命名为file
):
$ awk -i inplace 'NR<=4' file
$ cat file
1
2
3
4
说明:
$ awk -i inplace ' # edit is targetted to the original file (try without -i ...)
NR<=4 # output first 4 records
' file # file
您也可以退出NR==5
,如果您将程序的输出重定向到新文件(删除#
以获取操作),这将更快,这与{{1}相同}:
head -4 file > new_file
测试时,请不要先忘记$ awk 'NR==5{exit}1' file # > new_file
部分。