如何按行截断文件?

Cha*_*les 15 linux bash-scripting

我有大量文件,其中一些文件很长。如果它们更大,我想通过删除文件的末尾将它们截断到一定的大小。但我只想删除整行。我怎样才能做到这一点?感觉就像 Linux 工具链可以处理的那种事情,但我不知道正确的命令。

例如,假设我有一个包含 300 字节行的 120,000 字节文件,我试图将其截断为 10,000 字节。前 33 行应该保留(9900 字节),其余的应该被删除。我不想精确地削减 10,000 个字节,因为那会留下部分行。

当然,文件的长度不同,行的长度也不一样。

理想情况下,生成的文件会稍微短一些,而不是稍微长一些(如果断点在一条长线上),但这不是太重要,如果这样更容易的话,它可能会更长一点。我希望直接对文件进行更改(好吧,可能是新文件复制到别处,原始文件已删除,新文件已移动,但这与用户的 POV 相同)。将数据重定向到一堆地方然后返回的解决方案可能会损坏文件,我想避免这种情况......

Izz*_*zzy 16

这种sed方法很好,但循环所有行则不然。如果您知道要保留多少行(举个例子,我在这里使用 99),您可以这样做:

sed -i '100,$ d' myfile.txt
Run Code Online (Sandbox Code Playgroud)

说明:sed是一个正则表达式处理器。使用-i给定的选项,它直接处理文件(“内联”)——而不是仅仅读取它并将结果写入标准输出。100,$只是表示“从第 100 行到文件末尾”——后面跟着命令d,你可能猜对了它代表“删除”。简而言之,该命令的意思是:“从 myfile.txt 中删除从第 100 行到文件末尾的所有行”。100 是要删除的第一行,因为您要保留 99 行。

编辑:另一方面,如果您想保留日志文件,例如最后100 行:

[ $(wc -l myfile.txt) -gt 100 ] && sed -i "1,$(($(wc -l myfile.txt|awk '{print $1}') - 100)) d" myfile.txt
Run Code Online (Sandbox Code Playgroud)

这里发生了什么:

  • [ $(wc -l myfile.txt) -gt 100 ]: 仅当文件超过 100 行时才执行以下操作
  • $((100 - $(wc -l myfile.txt|awk '{print $1}'))): 计​​算要删除的行数(即文件的所有行,除了要保留的(最后)100 行)
  • 1, $((..)) d: 删除从第一行到计算行的所有行

编辑:由于刚刚编辑了问题以提供更多详细信息,因此我还将在回答中包含此附加信息。补充的事实是:

  • 文件应保留特定大小(10,000 字节)
  • 每行都有一个特定的字节大小(示例中为 300 字节)

根据这些数据,可以计算出保留为“/”的行数,在示例中这意味着 33 行。用于计算的 shell 术语:($((size_to_remain / linesize))至少在使用 Bash 的 Linux 上,结果是一个整数)。调整后的命令现在将显示为:

# keep the start of the file (OPs question)
sed -i '34,$ d' myfile.txt
# keep the end of the file (my second example)
[ $(wc -l myfile.txt) -gt 33 ] && sed -i "1,33 d" myfile.txt
Run Code Online (Sandbox Code Playgroud)

由于尺寸是预先知道的,因此不再需要嵌入到sed命令中的计算。但是为了灵活性,在一些 shell 脚本中可以使用变量。

对于基于文件大小的条件处理,可以使用以下“测试”结构:

[ "$(ls -lk $file | awk ' {print $5}')" -gt 100 ] &&
Run Code Online (Sandbox Code Playgroud)

这意味着:“如果 的大小$file超过 100kB,请执行...”(ls -lk在位置 5 以 kB 为单位列出文件大小,因此awk用于准确提取此文件)。


小智 2

如果使用/ sedwc则可以在之前的答案中避免复杂性。awk使用 OP 提供的示例(显示10000 字节之前的完整行):

awk '{i += (length() + 1); if (i <= 10000) print $ALL}' myfile.txt
Run Code Online (Sandbox Code Playgroud)

如果该字节不在行尾,还显示包含第 10000 个字节的完整行:

awk '{i += (length() + 1); print $ALL; if (i >= 10000) exit}' myfile.txt
Run Code Online (Sandbox Code Playgroud)

上面的答案假设:

  1. 文本文件是 Unix 行终止符 ( \n)。对于 Dos/Windows 文本文件 ( \r\n),更改length() + 1length() + 2
  2. 文本文件仅包含单字节字符。如果存在多字节字符(例如在unicode环境下),请设置环境LC_CTYPE=C以强制在字节级别进行解释。