如果我有一个包含许多行和列的分隔文件 ( data.txt
):
346 dfd asw 34
565 sd wdew 34
667 ffg wew 23
473 sa as 21
533 jhf qwe 54
以及另一个包含我要提取的行号的文件 ( positions.txt
)
3
5
8
如何使用该positions.txt
文件从中提取这些位置data.txt
?这是我期望的示例结果:
667 ffg wew 23
533 jhf qwe 54
答案1
简单地与awk
:
awk 'NR==FNR{ pos[$1]; next }FNR in pos' positions.txt data.txt
NR==FNR{ ... }
- 处理第一个输入文件(即positions.txt
):pos[$1]
- 累积位置(记录数)设置为pos
数组键next
- 跳转到下一条记录
FNR in pos
- 处理第二个输入文件时data.txt
(FNR
指示已从当前输入文件读取了多少条记录)。仅当当前记录号FNR
位于位置数组中时才打印记录pos
(按键搜索)
示例输出:
667 ffg wew 23
533 jhf qwe 54
...
答案2
首先sed
从positions.txt
文件创建一个脚本:
sed 's/$/p/' positions.txt
这将输出
3p
5p
8p
这个简单的脚本只会打印指定的行。
然后将其应用到data.txt
文件中。如果您正在使用bash
(或任何能够理解进程替换的 shell <( ... )
):
sed -n -f <( sed 's/$/p/' positions.txt ) data.txt
除了给定脚本显式打印的内容之外,-n
停止输出任何内容。sed
sed
根据给出的例子,这将产生
667 ffg wew 23
533 jhf qwe 54
如果不使用bash
,那么
sed 's/$/p/' positions.txt >filter.sed
sed -n -f filter.sed data.txt
rm -f filter.sed
...也会做同样的事情。
答案3
如果positions.txt
已排序,则也可以在一次遍历两个文件的情况下执行此操作,而无需positions.txt
完整存储。positions.txt
当满足上一个匹配行时,只需读取下一行:
$ awk -vpos=positions.txt 'function get() { getline num < pos }
BEGIN { get() } NR==num { print; get() }' data.txt
667 ffg wew 23
533 jhf qwe 54
实际上,这仅在两个文件都非常大或者您确实,真的内存不足。
答案4
我们可以通过简单的 for 循环来做到这一点
方法1使用sed和for循环
for i in `cat positions.txt`; do sed -n ""$i"p" data.txt ; done
输出
667 ffg wew 23
533 jhf qwe 54
方法2使用awk和for循环
for i in `cat positions.txt`; do awk -v i="$i" 'NR==i {print $0}' data.txt ;done
输出
667 ffg wew 23
533 jhf qwe 54