如何按行截断文件?


13

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

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

当然,文件的长度不同,行的长度也不尽相同。

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


删除了我的答案...我想字节大小的文件大小不太清楚,抱歉。也许您可以编辑您的问题并阐明这一部分(例如,举一个例子)?
slhck

@slhck:很抱歉看到您失去代表,只是因为我不清楚...让我看看是否可以解决该问题。
查尔斯

不用担心,我应该问一下,对不起:)
slhck 2012年

Answers:


1

如果使用sed/,wc则可以在以前的答案中避免/ 复杂性awk。使用OP提供的示例(显示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以强制在字节级别进行解释。

15

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

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

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

编辑:如果,另一方面,有您要保留的日志文件,例如最后一个 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,请执行...”(以5k为单位ls -lk列出文件大小,因此awk将其精确地提取出来)。


OP希望根据特定的字节大小(而不只是行数的长度)来剪切文件。我删除了涉及的答案head -n
slhck

@slhck谢谢您的通知。是的,OP只是编辑了他的问题,以使意图更加清晰。由于他有能力计算每行有多少字节,因此我的回答在原则上仍然有效-因为他可以计算要保留的行数,然后使用我的方法来处理文件。也许我在回答中对此做一句话。
Izzy

否-尺寸未知。那是一个例子。每个文件都有不同的大小,行的长度不规则。有些文件根本不需要被截断。
查尔斯

哦,再次...好吧,有些事情很难解释清楚(过多的刻面)。至于不需要截断的文件,可能是基于文件大小的?可以解决。但是,如果甚至不知道平均线径,那么这部分就很困难-我现在无法想到一个简单的解决方案(没有太多的开销)。
Izzy 2012年

我目前能想出的一切都涉及例如获取前n行,根据它们计算平均长度,然后使用该值。这样对您有帮助吗?
伊兹(Izzy)2012年

0

未能找到执行此操作的命令,我编写了一个快速脚本(未经测试):

#!/bin/sh

# Usage: $0 glob.* 25000
# where glob.* is a wildcard pattern and 25000 is the maximum number of bytes.

limit=20000
tmp=/tmp/trim
[[ "$2" == +([0-9]) ]] || limit=$2
limit=`expr $len + 1`
for file in $1;
do
    [[ `wc -c $file` -lt $limit ]] && continue
    head -c $file > $tmp
    sed '$d' $tmp
    $tmp > $file
done

-1

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

sed '$d' filename.txt

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


-1

我用尾巴做了类似的事情。在这种情况下,仅保留最后10,000行:

TMP=$(tail -n 10000 /path/to/some/file 2>/dev/null) && echo "${TMP}" > /path/to/some/file
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.