是否有一个工具(或选项sort
)可以重新排序文件的行,以便它们像另一个文件中的键一样排序?
例如我有一个数据文件:
T01F01475558 30
T01F022B3A17 31
T01F022EEDFD 19
T01F026E0209 19
另一个(对“关键”文件进行排序):
T01F022EEDFD
T01F026E0209
T01F022B3A17
T01F01475558
有没有办法对第一个文件进行排序,以便第一个字段与第二个文件的顺序相同?每个键都是唯一的(没有重复),并且每个文件中的行数相等。
是否存在我不知道的可以执行此操作的 UNIX 工具?
答案1
每个键都是唯一的(没有重复),并且每个文件中的行数相同。
这个假设非常重要。如果它成立,那么这个命令将完成这项工作(在 Bash 中):
paste <(nl key.file | sort -k 2 | cut -f 1) <(sort data.file) | sort -n | cut -f 2-
很少有工具使用制表符作为分隔符。因此制表符不能出现在 中key.file
(尽管它们可以出现在 中data.file
)。无论如何, 中的合理条目key.file
应该形成单个列,所以这应该不是问题。
解释:
nl
在 的每一行前面添加一个行号key.file
;这会使键本身移动到第二列;sort -k 2
根据第二列(即键)进行排序。然后键被 丢弃cut -f 1
。- 另
sort
一种排序方式是data.file
,由于前面的键是唯一的,所以这种默认排序相当于按照唯一的键进行排序。 -s的两个结果
sort
通过 合并paste
。如果没有第一个,cut
示例行将是:4 T01F01475558 T01F01475558 30
两个文件中的键的唯一性和键数量相等至关重要。实际上,两个
sort
-s 中的相同键在同一行离开时相遇paste
。由于您不需要重复的键来占用内存,因此cut
会尽快使用第一个。有了它,实际的示例行离开paste
是:4 T01F01475558 30
然后根据这些行的数值对它们进行排序。行号从 开始
nl
排在最前面,因此此操作引入了所需的顺序。- 最后
cut
丢弃第一列,保留来自的精确行data.file
,但按照所需的顺序。
或者你可以尝试这个(在 Bash 中测试):
while IFS='' read -r ; do
[ -n "$REPLY" ] && grep "^$REPLY " data.file
done <key.file
请注意,代码要求每个键后都有一个空格字符data.file
。
优点:
key.file
可以指定任意数量的键、重复的键、不存在的键。在这种情况下,不要考虑“排序”,而要考虑“逐行检索所需的行”。- 您可以流式输入(例如 stdin 而不是
key.file
,只需省略<key.file
)并动态获取输出。
缺点:
grep
会将键解释为正则表达式,这可能会适得其反。grep -F
但一般来说,您需要^
在模式中。read
很慢;grep
反复产卵很慢;data.file
反复打开很慢。