如何从 Unix 上的文本文件中提取预定范围的行?
-
01-07-2019 - |
题
我有大约 23000 行 SQL 转储,其中包含多个数据库的数据。我需要提取该文件的特定部分(即单个数据库的数据)并将其放入新文件中。我知道我想要的数据的起始行号和结束行号。
有谁知道 Unix 命令(或一系列命令)从文件中提取 16224 行和 16482 行之间的所有行,然后将它们重定向到一个新文件中?
解决方案
sed -n '16224,16482p;16483q' filename > newfile
来自 sed手册:
p - 打印出模式空间(标准输出)。该命令通常仅与 -n 命令行选项结合使用。
n - 如果未禁用自动打印,请打印模式空间,然后,无论如何,将模式空间替换为下一行输入。如果没有更多的输入,则在不处理任何命令的情况下退出。
q - 出口
sed
无需处理任何更多命令或输入。请注意,如果未使用 -n 选项禁用自动打印,则会打印当前模式空间。
sed 脚本中的地址可以采用以下任意形式:
数字指定行号将仅匹配输入中的该行。
可以通过指定逗号分隔的两个地址来指定地址范围。地址范围匹配从第一个地址匹配的位置,并一直持续到第二个地址匹配(包括)。
其他提示
sed -n '16224,16482 p' orig-data-file > new-file
其中 16224,16482 是起始行号和结束行号(含)。这是 1 索引的。 -n
抑制将输入作为输出回显,这显然是您不想要的;数字表示执行以下命令的行范围;命令 p
打印出相关行。
使用头/尾非常简单:
head -16482 in.sql | tail -258 > out.sql
使用 sed:
sed -n '16482,16482p' in.sql > out.sql
使用 awk:
awk 'NR>=10&&NR<=20' in.sql > out.sql
您可以使用“vi”,然后使用以下命令:
:16224,16482w!/tmp/some-file
或者:
cat file | head -n 16482 | tail -n 258
编辑:-只是为了添加解释,您使用 头-n 16482 显示前 16482 行然后使用 尾部-n 258 从第一个输出中获取最后 258 行。
还有另一种方法 awk
:
awk 'NR==16224, NR==16482' file
如果文件很大,最好 exit
读取最后所需的行后。这样,它就不会不必要地读取以下行:
awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file
perl -ne 'print if 16224..16482' file.txt > new_file.txt
# print section of file based on line numbers
sed -n '16224 ,16482p' # method 1
sed '16224,16482!d' # method 2
sed -n '16224,16482p' < dump.sql
cat dump.txt | head -16224 | tail -258
应该可以解决问题。这种方法的缺点是,您需要进行算术来确定 tail 的参数,并考虑是否希望“Between”包含结束行。
又快又脏:
head -16428 < file.in | tail -259 > file.out
可能不是最好的方法,但它应该有效。
顺便提一句:259 = 16482-16224+1。
我写了一个 Haskell 程序,名为 分离器 这正是这样做的:有一个 阅读我的发布博客文章.
您可以按如下方式使用该程序:
$ cat somefile | splitter 16224-16482
这就是全部内容。您将需要 Haskell 来安装它。只是:
$ cabal install splitter
你就完成了。我希望您发现这个程序很有用。
我们甚至可以在命令行中进行检查:
cat filename|sed 'n1,n2!d' > abc.txt
例如:
cat foo.pl|sed '100,200!d' > abc.txt
使用红宝石:
ruby -ne 'puts "#{$.}: #{$_}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf
站在boxxar的肩膀上,我喜欢这样:
sed -n '<first line>,$p;<last line>q' input
例如
sed -n '16224,$p;16482q' input
这 $
意思是“最后一行”,所以第一个命令使 sed
打印以 line 开头的所有行 16224
第二个命令使 sed
辞职 后 印刷线 16428
. 。(添加 1
为了 q
-boxxar 解决方案中的范围似乎没有必要。)
我喜欢这个变体,因为我不需要两次指定结束行号。我用它来测量 $
不会对性能产生不利影响。
我本来打算发布 head/tail 技巧,但实际上我可能只是启动 emacs。;-)
- Esc键-X 转到行 雷特 16224
- 标记 (控制键-空间)
- Esc键-X 转到行 雷特 16482
- Esc键-w
打开新的输出文件,CTL-Y保存
让我看看发生了什么事。
我会用:
awk 'FNR >= 16224 && FNR <= 16482' my_file > extracted.txt
FNR 包含从文件中读取的行的记录(行)号。
我编写了一个小型 bash 脚本,您可以从命令行运行该脚本,只要您更新 PATH 以包含其目录(或者您可以将其放置在 PATH 中已包含的目录中)。
用法:$捏文件名起始行结束行
#!/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
这可能对你有用(GNU sed):
sed -ne '16224,16482w newfile' -e '16482q' file
或利用 bash:
sed -n $'16224,16482w newfile\n16482q' file
我想在使用变量的脚本中做同样的事情,并通过在 $variable 周围加上引号以将变量名称与 p 分开来实现它:
sed -n "$first","$count"p imagelist.txt >"$imageblock"
我想将列表拆分到单独的文件夹中,并找到最初的问题并回答一个有用的步骤。(分割命令不是旧操作系统上的选项,我必须将代码移植到)。
接受答案中的 -n 有效。如果您愿意,这里还有另一种方法。
cat $filename | sed "${linenum}p;d";
这会执行以下操作:
- 通过管道输入文件的内容(或根据需要输入文本)。
- sed 选择给定的行,打印它
- d 需要删除行,否则 sed 将假定所有行最终都会被打印。即,如果没有 d,您将获得所选行打印两次的所有行,因为您有 ${linenum}p 部分要求打印它。我很确定 -n 基本上与这里的 d 做同样的事情。
由于我们正在讨论从文本文件中提取文本行,因此我将给出一种特殊情况,即您想要提取与特定模式匹配的所有行。
myfile content:
=====================
line1 not needed
line2 also discarded
[Data]
first data line
second data line
=====================
sed -n '/Data/,$p' myfile
将打印 [Data] 行和其余部分。如果您想要从 line1 到模式的文本,请键入:sed -n '1,/Data/p' myfile.此外,如果您知道两种模式(最好在文本中是唯一的),则可以使用匹配来指定范围的开始行和结束行。
sed -n '/BEGIN_MARK/,/END_MARK/p' myfile