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

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


当前回答

使用head/tail非常简单:

head -16482 in.sql | tail -258 > out.sql

使用sed:

sed -n '16224,16482p' in.sql > out.sql

使用awk:

awk 'NR>=16224&&NR<=16482' in.sql > out.sql

其他回答

也许,你会给这个简陋的脚本一个机会;-)

#!/usr/bin/bash

# Usage:
#   body n m|-m

from=$1
to=$2

if [ $to -gt 0 ]; then
# count $from the begin of the file $to selected line
    awk "NR >= $from && NR <= $to {print}"
else
# count $from the begin of the file skipping tailing $to lines
    awk '
    BEGIN   {lines=0; from='$from'; to='$to'}
            {++lines}
    NR >= $from {line[lines]=$0}
    END     {for (i = from; i < lines + to + 1; i++) {
                print line[i]
            }
    }'
fi

输出:

$ seq 20 | ./body.sh 5 15
5
6
7
8
9
10
11
12
13
14
15

$ seq 20 | ./body.sh 5 -5
5
6
7
8
9
10
11
12
13
14
15

我编写了一个小型bash脚本,您可以从命令行运行它,只要您更新PATH以包含它的目录(或者您可以将它放在PATH中已经包含的目录中)。

用法:$ pinch filename起始行结束行

#!/bin/bash
# Display line number ranges of a file to the terminal.
# Usage: $ pinch filename start-line end-line
# By Evan J. Coon

FILENAME=$1
START=$2
END=$3

ERROR="[PINCH ERROR]"

# Check that the number of arguments is 3
if [ $# -lt 3 ]; then
    echo "$ERROR Need three arguments: Filename Start-line End-line"
    exit 1
fi

# Check that the file exists.
if [ ! -f "$FILENAME" ]; then
    echo -e "$ERROR File does not exist. \n\t$FILENAME"
    exit 1
fi

# Check that start-line is not greater than end-line
if [ "$START" -gt "$END" ]; then
    echo -e "$ERROR Start line is greater than End line."
    exit 1
fi

# Check that start-line is positive.
if [ "$START" -lt 0 ]; then
    echo -e "$ERROR Start line is less than 0."
    exit 1
fi

# Check that end-line is positive.
if [ "$END" -lt 0 ]; then
    echo -e "$ERROR End line is less than 0."
    exit 1
fi

NUMOFLINES=$(wc -l < "$FILENAME")

# Check that end-line is not greater than the number of lines in the file.
if [ "$END" -gt "$NUMOFLINES" ]; then
    echo -e "$ERROR End line is greater than number of lines in file."
    exit 1
fi

# The distance from the end of the file to end-line
ENDDIFF=$(( NUMOFLINES - END ))

# For larger files, this will run more quickly. If the distance from the
# end of the file to the end-line is less than the distance from the
# start of the file to the start-line, then start pinching from the
# bottom as opposed to the top.
if [ "$START" -lt "$ENDDIFF" ]; then
    < "$FILENAME" head -n $END | tail -n +$START
else
    < "$FILENAME" tail -n +$START | head -n $(( END-START+1 ))
fi

# Success
exit 0

又快又脏:

head -16428 < file.in | tail -259 > file.out

可能不是最好的方法,但应该有用。

顺便说一下:259 = 16482-16224+1。

只是对上面给出的3个解决方案进行了基准测试,这对我来说是可行的:

awk sed “头+尾”

3个解决方案的积分归属:

@boxxar @avandeursen @wds @manveru @sibaz @SOFe @fedorqui“所以停止伤害” @Robin A. Meade


我正在使用我在服务器上找到的一个巨大的文件:

# wc fo2debug.1.log
   10421186    19448208 38795491134 fo2debug.1.log

38gb, 1040万行。

是的,我有一个对数问题。:))


下注吧!


从文件开始获取256行。

# time sed -n '1001,1256p;1256q' fo2debug.1.log | wc -l
256

real    0m0,003s
user    0m0,000s
sys     0m0,004s

# time head -1256 fo2debug.1.log | tail -n +1001 | wc -l
256

real    0m0,003s
user    0m0,006s
sys     0m0,000s

# time awk 'NR==1001, NR==1256; NR==1256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,002s
user    0m0,004s
sys     0m0,000s

Awk赢了。在sed和“头+尾”之间,技术并列第二。


在文件的前三分之一处获得256行。

# time sed -n '3473001,3473256p;3473256q' fo2debug.1.log | wc -l
256

real    0m0,265s
user    0m0,242s
sys     0m0,024s

# time head -3473256 fo2debug.1.log | tail -n +3473001 | wc -l
256

real    0m0,308s
user    0m0,313s
sys     0m0,145s

# time awk 'NR==3473001, NR==3473256; NR==3473256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,393s
user    0m0,326s
sys     0m0,068s

Sed赢了。接着是“head+tail”,最后是awk。


在文件的第二个三分之一处获得256行。

# time sed -n '6947001,6947256p;6947256q' fo2debug.1.log | wc -l
A256

real    0m0,525s
user    0m0,462s
sys     0m0,064s

# time head -6947256 fo2debug.1.log | tail -n +6947001 | wc -l
256

real    0m0,615s
user    0m0,488s
sys     0m0,423s

# time awk 'NR==6947001, NR==6947256; NR==6947256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,779s
user    0m0,650s
sys     0m0,130s

同样的结果。

Sed赢了。接着是“head+tail”,最后是awk。


在文件末尾获得256行。

# time sed -n '10420001,10420256p;10420256q' fo2debug.1.log | wc -l
256

real    1m50,017s
user    0m12,735s
sys     0m22,926s

# time head -10420256 fo2debug.1.log | tail -n +10420001 | wc -l
256

real    1m48,269s
user    0m42,404s
sys     0m51,015s

# time awk 'NR==10420001, NR==10420256; NR==10420256 {exit}' fo2debug.1.log | wc -l
256

real    1m49,106s
user    0m12,322s
sys     0m18,576s

突然,一个转折!

“头+尾”赢了。接着是awk,最后是sed。


(几个小时后……)

对不起伙计们!

我上面的分析是做分析时一个基本缺陷的例子。

缺陷在于不深入了解用于分析的资源。

在本例中,我使用了一个日志文件来分析其中特定行数的搜索性能。

使用3种不同的技术,在文件中的不同位置进行搜索,比较每个位置上技术的性能,并检查搜索结果是否随着文件中进行搜索的位置而变化。

我的错误在于假定日志文件中的内容具有某种同质性。

实际情况是,长行更频繁地出现在文件的末尾。

因此,对于一种给定的技术,较长的搜索(接近文件末尾)更好的明显结论可能是有偏见的。事实上,这种技术在处理较长的队伍时可能会更好。还有待证实。

由于我们讨论的是从文本文件中提取文本行,所以我将给出一个特殊情况,即您希望提取与某个模式匹配的所有行。

myfile content:
=====================
line1 not needed
line2 also discarded
[Data]
first data line
second data line
=====================
sed -n '/Data/,$p' myfile

将打印[Data]行和其余部分。如果想要从第一行到模式的文本,输入:sed -n '1,/Data/p' myfile。此外,如果您知道两个模式(最好在文本中是唯一的),则可以使用匹配指定范围的开始行和结束行。

sed -n '/BEGIN_MARK/,/END_MARK/p' myfile