我有一个以下结构的文件:
4 1:4 3:1 6:1 56:2 57:4 58:7 59:1 66:2
1 2:1 56:1 57:1 58:2 59:2 65:1
8 1:2 2:1 3:8 12:1 56:1 57:2 58:2 59:2 66:1 67:2
我需要做的是将与56和57相关的值切换为与58和59相关的值:
4 1:4 3:1 6:1 56:7 57:1 58:2 59:4 66:2
1 2:1 56:2 57:2 58:1 59:1 65:1
8 1:2 2:1 3:8 12:1 56:2 57:2 58:1 59:2 66:1 67:2
目前我正在尝试使用以下内容执行至少两列的替换:
awk '{
for ( i=2;i<=NF;i++ )
{
split(, a, ":")
arr[a[1]] = a[2]
}
}
END {
n = asorti(arr, dest)
ORS=
for ( i=1; i<=n; i++ )
{
if ( dest[i] != 56 && dest[i] != 58 )
print dest[i] ":" arr[dest[i]]
else
{
if ( dest[i] == 56 )
print dest[i] ":" arr[dest[i+2]]
if ( dest[i] == 58 )
print dest[i] ":" arr[dest[i-2]]
}
}
}' file
但是,这看起来很笨重,最终索引没有正确排序。将欣赏任何其他解决方案。
如果你可以依赖订购总是56,57,58,59,那么你可以用sed做到这一点:
sed -E 's/(56:)([0-9]+)(.*57:)([0-9]+)(.*58:)([0-9]+)(.*59:)([0-9]+)/\1\6\3\8\5\2\7\4/' file
只需捕获所有零件并在更换中重新洗牌。
奇数编号的捕获组指的是“标签”和任何主要内容,除了在第一种情况下我们不必触摸该部分线路。偶数编号指的是数值。
GNU awk
解决方案:
awk '{
r=gensub(/\<(56:)([0-9]+) (57:)([0-9]+) (58:)([0-9]+) (59:)([0-9]+)/,
"\\1\\6 \\3\\8 \\5\\2 \\7\\4", "g");
print r
}' file
输出:
4 1:4 3:1 6:1 56:7 57:1 58:2 59:4 66:2
1 2:1 56:2 57:2 58:1 59:1 65:1
8 1:2 2:1 3:8 12:1 56:2 57:2 58:1 59:2 66:1 67:2
gensub(regexp, replacement, how [, target])
在目标字符串
target
中搜索正则表达式regexp
的匹配项。如果how
是以'g
'或'G
'(“global”的缩写)开头的字符串,则将regexp
的所有匹配替换为replacement
。