如何按行截断文件?

如何按行截断文件?

我有大量文件,其中一些文件很长。如果文件较大,我想通过删除文件末尾来将它们截断为一定大小。但我只想删除整行。我该怎么做?这感觉像是 Linux 工具链可以处理的事情,但我不知道正确的命令。

例如,假设我有一个 120,000 字节的文件,每行 300 字节,我想将其截断为 10,000 字节。前 33 行应保留(9900 字节),其余部分应被截断。我不想在 10,000 字节处截断,因为那样会留下部分行。

当然,文件的长度是不同的,并且行的长度也不都是相同的。

理想情况下,生成的文件会稍微短一些而不是稍微长一些(如果断点在一条长线上),但这并不重要,如果这样更容易,文件可以稍微长一些。我希望直接对文件进行更改(好吧,可能是将新文件复制到其他地方,删除原始文件,然后移动新文件,但从用户的角度来看,这是一样的)。将数据重定向到一堆地方然后再返回的解决方案可能会损坏文件,我想避免这种情况……

答案1

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

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

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

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

上述答案假设:

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

答案2

这种sed方法很好,但循环遍历所有行就不行了。如果你知道要保留多少行(为了举例,我在这里使用 99 行),你可以这样做:

sed -i '100,$ d' myfile.txt

解释: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

这里发生了什么:

  • [ $(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

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

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

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

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

答案3

您可以使用 Linux 命令 sed 从文件中删除行。以下命令删除 filename.txt 的最后一行:

sed '$d' filename.txt

使用 awk 或 find,您可以搜索与 sed 命令匹配的模式。首先,使用 awk 或 find 搜索要缩短的文件,然后使用 sed 删除行。

答案4

我对 tail 做了类似的事情。在这种情况下,只保留最后 10,000 行:

TMP=$(tail -n 10000 /path/to/some/file 2>/dev/null) && echo "${TMP}" > /path/to/some/file

相关内容