使用sed在1行中打印多个匹配项

时间:2011-12-25 22:47:51

标签: sed

我有一个Makefile,它有变量versionbuild(这些不是唯一的变量,可以按不同的顺序定义)。仅使用sed,我想将这些值组合成一个版本字符串。

到目前为止,我已经:

sed -n -e '/=/{s/version.*=\(.*\)/\1\./p;s/build.*=\(\d*\)*/\1/p}' Makefile

但两个值都用换行符分隔。以上产生以下输出:

0.8.2.
1

我想:

  

0.8.2.1

我尝试了N,但无法确定如何在此引用中使用它。

为什么'仅限'限制?我想学习它,这对我来说是最好的方式。

独立样本:

sed -n -e '/=/ {s/version.*=\(.*\)/\1\./p;s/build.*=\(\d*\)*/\1/p}' <<EOF
foo=1
version=0.8.2
bar=2
build=1
bam=bug-AWWK
EOF

4 个答案:

答案 0 :(得分:4)

以下是基于相同的想法:存储版本和内部版本号,然后在输入结束时打印它们。

当涉及到存储时,sed具有模式空间,该空间以当前行的值开始,以及保持空间,可用于在过程持续时间内保存值。版本应该预先设置为保留空间中的值,这可以通过使用G将保留空间附加到模式空间来实现。构建应附加到保留空间,可以使用H完成。要删除H创建的换行符,将保留空间移回模式空间。在这两种情况下,GH创建的换行符都会被s///删除,然后返回到h的保留空间。输入的结尾由$地址表示,在该地址处,保留空间被移回模式空间并打印。它看起来更短:

sed -n -e '/^version.*=/ {s/[^=]*=//; G; s/\n//; h; } ' \
       -e '/^build.*=/ { s/[^=]*=//; H; g; s/\n/./; h; } ' \
       -e '$ { g; P; }'

这会在字符串的末尾产生换行符,但希望这不会成为问题。

awk系列实用程序支持变量,使任务更加简单。它们具有特殊变量OFS,输出字段分隔符和ORS,即输出记录分隔符。 awk的print在每个参数之间输出OFS,在最后输出ORS。特殊模式END在输入结束后匹配。

awk -v OFS=. -v ORS='' \
    '/^version.*=/ {sub(/^[^=]*=/, "");  version=$0;} \
     /^build.*=/ {sub(/^[^=]*=/, ""); build=$0;} \
     END {print version, build;}'

如果您不关心尾随点,并且可以确定makefile中版本和构建行的顺序:

awk -v ORS=. '/(version|build).*=/ { sub(/^[^=]*=/, ""); print; } '

语言表达能力的持续向上是perl。 perl的END具有与awk类似的功能,标记要在进程结束时运行的块。哈希可用于存储完整版本号的部分,允许行匹配并存储版本和构建以组合成一行。

perl -n -e '$ver{$1} = $2 if /^(version|build)[^=]*=(.*)/; \
            END {$,="."; print @ver{"version","build"}};'

虽然使用sed是一项有趣的练习,但练习中的价值在于通过练习来强化自己。如果您必须转向其他人,最好不要专注于您尝试solve the problem的方式,而是找出推荐的方法。你会了解更多。

答案 1 :(得分:1)

尝试使用makefile:

 sed -rn -e '/^(version|build)/{s#^.*=##;H;}' -e'${x;s#\n##;s#\n#\.#;p}' makefile

使用示例文本进行测试:

kent$  sed -rn -e '/^(version|build)/{s#^.*=##;H;}' -e'${x;s#\n##;s#\n#\.#;p}' <<<"foo=1
dquote> version=0.8.2
dquote> bar=2
dquote> build=1
dquote> bam=bug-AWWK
dquote> EOF"
0.8.2.1

如果版本显示在版本之前:

kent$  sed -rn -e '/^(version|build)/{s#^.*=##;H;}' -e'${x;s#\n##;s#\n#\.#;p}' <<<"foo=1
bar=2
build=1
bam=bug-AWWK
version=100.8.2"
1.100.8.2

答案 2 :(得分:0)

这可能对您有用:

cat makefile | 
sed '/^\(version\|build\)/H;${x;s/^\(\nbuild.*\)\(\n.*\)/\2\1/;s/^.*=\(.*\)\n.*=\(.*\)/\1.\2/p};d'
0.8.2.1
tac makefile | 
sed '/^\(version\|build\)/H;${x;s/^\(\nbuild.*\)\(\n.*\)/\2\1/;s/^.*=\(.*\)\n.*=\(.*\)/\1.\2/p};d'
0.8.2.1

如果版本在构建之前或之后没有打扰,那么:

sed '/^\(version\|build\)/H;${x;s/^.*=\(.*\)\n.*=\(.*\)/\1.\2/p};d'
0.8.2.1

阅读@outis解决方案后,这是他的平面浏览解决方案的改进版本:

 sed '/^version=/{s///;G;h};/^build=/{s//./;H};${g;s/\n//gp};d' makefile

答案 3 :(得分:0)

如果您对awk开放,那么这是另一种解决方案。防止因输入sed代码而导致的手指痉挛。 No offence to the brilliant solutions offered by potong and kent ;)

awk -F"=" '
BEGIN{i=1}
(/version|build/){a[i]=$NF;i++}
END{for(i=1;i<=2;i++) if(i==1) {printf a[i]"."} else printf a[i]}' Makefile