如何从Unix上的文本文件中提取预定范围的行?

Ada*_*ter 505 unix command-line text-processing sed

我有一个~23000行的SQL转储包含几个数据库的数据.我需要提取此文件的某个部分(即单个数据库的数据)并将其放在一个新文件中.我知道我想要的数据的起始行和结束行号.

有没有人知道一个Unix命令(或一系列命令)从第16224和16482行之间的文件中提取所有行,然后将它们重定向到一个新文件?

小智 750

sed -n '16224,16482p;16483q' filename > newfile
Run Code Online (Sandbox Code Playgroud)

sed手册:

p - 打印出图案空间(到标准输出).此命令通常仅与-n命令行选项一起使用.

n - 如果未禁用自动打印,则打印图案空间,然后,无论如何,将图案空间替换为下一行输入.如果没有更多输入,那么sed退出而不再处理任何命令.

q - 退出sed而不处理更多命令或输入.请注意,如果未使用-n选项禁用自动打印,则会打印当前模式空间.

sed脚本中的地址可以采用以下任何一种形式:

number 指定行号仅匹配输入中的该行.

可以通过指定用逗号(,)分隔的两个地址来指定地址范围.地址范围匹配从第一个地址匹配的行开始,并继续直到第二个地址匹配(包含).

  • 如果像我一样,你需要在一个非常大的文件上执行此操作,如果你在下一行添加一个quit命令会有所帮助.然后是'sed -n'16224,16482p; 16483q'filename`.否则sed将继续扫描直到结束(或至少我的版本). (164认同)
  • @MilesRout的人似乎在问"为什么要进行downvote?" 很多时候,也许你的意思是"我不在乎"而不是"无人问津" (7认同)
  • 我很好奇这是否会修改原始文件。我备份它以防万一,看起来这并没有像预期的那样修改原始文件。 (3认同)
  • @安迪格罗夫。要就地修改文件,请使用“-i”参数。否则不会修改该文件。 (2认同)
  • @wds - 您的评论很值得上升到顶部的答案。它可以区分白天和黑夜。 (2认同)

JXG*_*JXG 199

sed -n '16224,16482 p' orig-data-file > new-file
Run Code Online (Sandbox Code Playgroud)

16224,16482是起始行号和结束行号,包括在内.这是1索引的. -n抑制将输入作为输出回显,这显然是你不想要的; 数字表示使以下命令操作的行数范围; 该命令p打印出相关的行.

  • 好吧,从这里的答案(http://stackoverflow.com/a/2237656/1054260)来看,似乎可以通过以下方式停止在范围的末尾:`sed -n'16224,16482p; 16482q' orig-data-file> new-file`. (39认同)
  • 我喜欢空白; 它保持可读性. (9认同)
  • 在大文件上,上述命令将在找到所需范围后继续遍历整个文件.有没有办法让sed在输出范围后停止处理文件? (7认同)
  • 你为什么要放入一个不必要的空间,然后引用?(当然,制造不必要的问题并解决它们是半数计算机科学的本质,但我的意思是除了那个原因......) (5认同)

man*_*eru 86

使用头/尾非常简单:

head -16482 in.sql | tail -258 > out.sql
Run Code Online (Sandbox Code Playgroud)

使用sed:

sed -n '16482,16482p' in.sql > out.sql
Run Code Online (Sandbox Code Playgroud)

使用awk:

awk 'NR>=10&&NR<=20' in.sql > out.sql
Run Code Online (Sandbox Code Playgroud)

  • 即使添加了 q 选项,第一个在大文件上的头部和尾部 WAYYYY 比 sed 版本更快。一分钟后,头部版本即时和 sed 版本我 Ctrl-C ......谢谢 (5认同)
  • 值得注意的是,为了保持与问题相同的行号,sed命令应该是`sed -n 16224,16482p'in.sql> out.sql`并且awk命令应该是'awk'NR> = 16224 && NR <= 16482 'in.sql> out.sql` (3认同)
  • 另外值得一提的是,在第一个例子`head -16482 in.sql |的情况下 tail - $((16482-16224))> out.sql`将计算结果保留为bash (3认同)
  • 第二个和第三个选项都可以,但第一个比许多替代方案慢,因为它使用 2 个命令,其中 1 就足够了。它还需要计算才能为“tail”获得正确的参数。 (2认同)
  • 也可以使用“ tail -n +16224”来减少计算 (2认同)

小智 30

您可以使用'vi'然后使用以下命令:

:16224,16482w!/tmp/some-file
Run Code Online (Sandbox Code Playgroud)

或者:

cat file | head -n 16482 | tail -n 258
Run Code Online (Sandbox Code Playgroud)

编辑: - 只是添加说明,你使用head -n 16482显示第一个16482行然后使用tail -n 258来获得第一个输出中的最后258行.

  • head -n 16482 file | tail -n 258应该更好用 (7认同)
  • 而不是vi你可以使用ex,即vi减去交互式控制台的东西. (2认同)
  • 您不需要“cat”命令;`head` 可以直接读取文件。这比许多替代方案要慢,因为它使用 2 个(如图所示的 3 个)命令,其中 1 个命令就足够了。 (2认同)
  • @JonathanLeffler 你错了。它非常快。我在几秒钟内从一个 500k 行的 2G 文件中提取了 200k 行,大约 1G(没有 `cat`)。其他解决方案至少需要几分钟。GNU 上最快的变体似乎是 `tail -n +XXX filename | 头XXX`。 (2认同)

fed*_*qui 25

还有另一种方法awk:

awk 'NR==16224, NR==16482' file
Run Code Online (Sandbox Code Playgroud)

如果文件很大,那么exit在读完最后一行后可能会很好.这样它就不会不必要地读取文件直到最后:

awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file
Run Code Online (Sandbox Code Playgroud)

  • 1+ 通过使用`print 来节省运行时间和资源;退出`。谢谢 ! (2认同)

Tas*_*nou 19

人们试图绞尽脑汁计算一个间隔head | tail组合的间隔是想太多了。

以下是无需计算任何内容即可获得“16224 - 16482”范围的方法:

cat file | head -n +16482 | tail -n +16224
Run Code Online (Sandbox Code Playgroud)

解释:

  • 指示/+命令“向上/”(分别)指定的行号(从文件开头算起)headtail

  • 类似地, a-指示它们“分别文件末尾开始计算指定的行号

  • 上面显示的解决方案简单地使用head第一个“将所有内容保留到顶部数字”,然后使用tail第二个“保留从底部数字向上的所有内容”,从而定义我们感兴趣的范围(无需计算间隔)。

  • 我发现用名称比用数字更容易理解;我将其写为 `head -n +"$last_line" "$full_log_file" | tail -n +“$first_line”&gt;“$cropped_log_file”` (2认同)

小智 17

perl -ne 'print if 16224..16482' file.txt > new_file.txt
Run Code Online (Sandbox Code Playgroud)


Cet*_*tra 9

 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2
Run Code Online (Sandbox Code Playgroud)


JP *_*ine 6

cat dump.txt | head -16224 | tail -258
Run Code Online (Sandbox Code Playgroud)

应该做的伎俩.这种方法的缺点是你需要做算术来确定尾部的参数,并考虑你是否希望'between'包括结束行.

  • 你不需要`cat`命令; `head`可以直接读取文件.这比许多替代方案慢,因为它使用2(如图所示3)命令,其中1就足够了. (4认同)
  • @JonathanLeffler 这个答案最容易阅读和记住。如果您真的关心性能,您一开始就不会使用 shell。让特定工具专注于特定任务是一种很好的做法。此外,“算术”可以使用`|来解决。尾部 -$((16482 - 16224))`。 (2认同)

cub*_*bex 5

sed -n '16224,16482p' < dump.sql


Til*_*gel 5

我站在Boxxar的肩膀上,像这样:

sed -n '<first line>,$p;<last line>q' input
Run Code Online (Sandbox Code Playgroud)

例如

sed -n '16224,$p;16482q' input
Run Code Online (Sandbox Code Playgroud)

$意思是“最后行”,所以第一个命令使sed打印开始的行中的所有行16224和所述第二命令使sed退出打印线16428。(添加1q在boxxar的解决方案-范围似乎没有必要。)

我喜欢这种变体,因为我不需要两次指定结束行号。而且我测量到使用$不会对性能产生不利影响。