我有包含一行的大型 (MB) 文本文件,需要提取 string1 和 string2 第一次出现之间的部分。我发现了很多食谱,但大多数适用于单独的行或提取到第二个字符串的最后一次出现。我发现使用参数 infile、outfile、string1、string2 可以工作的是:
#!/bin/bash
a="$(cat $1)" ## copy file1 to a
a="$(echo "${a#*"$3"}")" ## cut up to (including) str1
echo "${a%%"$4"*}" > $2 ## part after str1 up to str2
## where the last line may also be
printf '%s' "${a%%"$4"*}" > $2 ## part after str1 up to str2
但这两个版本都非常慢(我必须为每个文件重复多次)。怎么提速?
答案1
与 OP 聊天时的一些讨论表明,该单行是来自网络查询的 JSON。使用诸如jq . < input_file
或 之类的工具漂亮地打印此文件python -mjson.tool input_file
,使文件更适合传统的逐行处理。
进一步的讨论表明这是一个书目查找,其目的是生成一个平面文件。jq
OP 认为以下程序(我的第一个程序)足够快。
#!/bin/bash
jq -r < "$1" '.response.docs[] |
(" Title: "+.title[]),
(" Authors: "+(.author|join(""))),
(" Bibcode: "+.bibcode),
(" AltBibcode: "+(.alternate_bibcode//[] | join(" : "))),
(" "+(.abstract//"NOABSTRACT")),
""' | fmt | sed 's/^ \?//'
有几个微妙的点。我们的愿望是包装摘要而不是一长行,因此输出通过 发送fmt
。该程序具有以下属性:以不同缩进开头的行不是连接在一起,因此在文本中添加 4/3/4/3/2 空格模式,例如“标题:”。然后,fmt 实际上只是包装了摘要,缩进了 2 个空格。然后使用 sed 删除其他标题行上的 3 或 4 个空格。这并不完美,很长的作者列表也会被包装起来。更好的 sed 程序可以将作者重新连接到一行,删除空白的 AltBibcode 条目等。
输出格式经过精心设计,可以通过 awk 一行脚本进行后期处理
awk -vRS='' -vORS=$'\n\n' !/NOABSTRACT/'
删除没有摘要的条目。
答案2
$ sed -e 's/stringA/\n/;s/.*\n//;s/stringB.*//' file
删除 stringA 之前的代码分两个阶段完成(将 stringA 更改为换行符,然后删除第一行),而不是更明显的“删除 stringA 之前的所有内容”,因为删除需要达到第一的stringA 的出现而不是最后一个。与许多其他工具(例如 python 和 perl)不同,sed 不支持非贪婪正则表达式。
$ perl -lpe '
my($sa, $sb) = qw/stringA stringB/;
my $p2 = index($_, $sb);
my $p1 = index($_, $sa)+length($sa);
$_ = substr($_, $p1, $p2-$p1);
' file