在 osx shell 中,给定一个包含这些行的流,其中第一个标记是键,该行上的第一个字符将始终匹配[a-z]
,其余标记将始终只是数字,它们的数量是可变的,并且只有单个空格分离令牌:
key [1] [...] [n]
---- --------------------
key1 17 89 52
key2 5 189 6 3 5 21
如何发出以下输出(与每行上的标记数量无关)而不只是一遍又一遍地进行替换?
17 key1
89 key1
52 key1
5 key2
189 key2
6 key2
3 key2
5 key2
21 key2
(交换键和数字,或者每行保持一行由空格分隔,而不是像 那样的换行符key1 17 key1 89 key1 52
,因为我可以交换标记或轻松地将它们分成多行)。
我目前正在使用sed
连续替换每个下一个无钥匙号码,但这似乎效率低下,而且我必须确保我管道的sed
次数多于令牌的最大数量,这可能会增加(而且确实如此,否则你猜我为什么会在这里?):
sed -E 's/^([a-z][^ ]*) ([0-9]+) /\2 \1\n\1 /g' filename.txt | sed ... | sed ...
如果我有时间去深入研究,awk
我相信这会起作用。也许cut
可以完成这项工作或可以有效地使用代币的其他工具之一。
您如何在代码和处理时间内有效地完成此操作?
答案1
您可以使用 awk 来实现此目的
awk '{ for(i = 2; i <= NF; i++) { print $i,$1; } }' file
for 循环从第二个字段到最后一个字段,打印每个字段并附加第一个字段
答案2
sed
非常适合这项任务。只需稍微调整一下你的 sed 代码,我们就有:
sed -E '
s/^([a-z][^ ]*) ([0-9]+)/\2 \1\n\1/
/\n/P;D
' filename.txt
输出:
17 key1
89 key1
52 key1
5 key2
189 key2
6 key2
3 key2
5 key2
21 key2
解释:
- 您已经知道我从您那里获取的替代 s/// 命令,只需删除
global /g flag
. - 基本思想是,我们查看前两个元素,翻转它们,同时保存第一个元素的副本(翻转之前)并
\n
在翻转操作后放置一个换行符,以便我们可以使用该P
命令,该命令打印直到模式空间中的第一个换行符。 P
用a限定/\n/
以避免无限循环。- 删除
D
模式空间中的第一个换行符以及模式空间的剩余部分,将控制权带回脚本的顶部。 IOW,您所做的是提供隐式循环机制。 - 当模式空间最终被 的连续过程吃掉时,当前行的循环结束
s/// --- P --- D --- s/// --- P --- D ...........
。 - 之后,
sed
开始一个新的阅读周期,然后你就知道会发生什么了.... HTH。