我有两个文件:
我想打印第一个文件中的行,这些行由第二个文件中的行索引。我目前的解决方案是这样做
while read index
do
sed -n ${index}p $file1
done < $file2
它基本上逐行读取索引文件并运行sed以打印该特定行。问题是它对于大型索引文件(数千和数万行)来说速度很慢。
是否可以更快地完成此操作?我怀疑awk在这里很有用。
我搜索到最好,但只能找到人们试图打印行范围而不是第二个文件索引。
更新
索引通常不会改组。期望这些行以索引文件中索引定义的顺序出现。
实施例
文件1:
this is line 1
this is line 2
this is line 3
this is line 4
文件2:
3
2
预期输出为:
this is line 3
this is line 2
答案 0 :(得分:3)
这个awk脚本做你想要的:
$ cat lines
1
3
5
$ cat strings
string 1
string 2
string 3
string 4
string 5
$ awk 'NR==FNR{a[$0];next}FNR in a' lines strings
string 1
string 3
string 5
第一个块仅针对第一个文件运行,其中当前文件FNR
的行号等于总行号NR
。它为应打印的每个行号在数组a
中设置一个键。 next
跳过其余说明。对于包含字符串的文件,如果行号在数组中,则执行默认操作(因此打印行)。
答案 1 :(得分:3)
如果我理解正确,那么
awk 'NR == FNR { selected[$1] = 1; next } selected[FNR]' indexfile datafile
应该有效,假设索引按升序排序,或者您希望在数据文件中按行顺序打印行,而不管索引的排序方式如何。其工作原理如下:
NR == FNR { # while processing the first file
selected[$1] = 1 # remember if an index was seen
next # and do nothing else
}
selected[FNR] # after that, select (print) the selected lines.
如果未对索引进行排序,则应按照它们在索引中出现的顺序打印行:
NR == FNR { # processing the index:
++counter
idx[$0] = counter # remember that and at which position you saw
next # the index
}
FNR in idx { # when processing the data file:
lines[idx[FNR]] = $0 # remember selected lines by the position of
} # the index
END { # and at the end: print them in that order.
for(i = 1; i <= counter; ++i) {
print lines[i]
}
}
这也可以内联(在++counter
和index[FNR] = counter
之后使用分号,但我可能会将其放在一个文件中,比如foo.awk
,然后运行{{1使用索引文件
awk -f foo.awk indexfile datafile
和数据文件
1
4
3
这将打印
line1
line2
line3
line4
剩下的警告是,这假设索引中的条目是唯一的。如果这也是一个问题,那么您必须记住索引位置列表,在扫描数据文件时将其拆分并记住每个位置的行。那就是:
line1
line4
line3
最后,这是问题中代码的功能等价物。你必须要为自己的用例做些多么复杂的事情。
答案 2 :(得分:2)
使用nl
对字符串文件中的行进行编号,然后使用join
合并两者:
~ $ cat index
1
3
5
~ $ cat strings
a
b
c
d
e
~ $ join index <(nl strings)
1 a
3 c
5 e
如果您想要反向(在索引中显示 NOT 的行):
$ join -v 2 index <(nl strings)
2 b
4 d
还要注意@glennjackman的评论:如果你的文件没有按词汇排序,那么你需要在传入之前对它们进行排序:
$ join <(sort index) <(nl strings | sort -b)
答案 3 :(得分:0)
为了完成使用awk的答案,这里是Python中的一个解决方案,您可以在bash脚本中使用:
cat << EOF | python
lines = []
with open("$file2") as f:
for line in f:
lines.append(int(line))
i = 0
with open("$file1") as f:
for line in f:
i += 1
if i in lines:
print line,
EOF
这里唯一的优点是Python比awk更容易理解:)。