sed:从字符串中提取版本号

6

输入:adcheck (CentrifyDC 4.4.3-421)

期望的输出结果:4.4.3

我认为可行的方法:

/usr/share/centrifydc/bin/adcheck --version | sed -n '/Centrify DC /,/-/p'

但是这没有输出任何内容吗?

谢谢!

8个回答

6
你的解决方案无法实现,因为你试图使用地址选择一行中的一部分,但是地址只能选择一堆行。你的代码/Centrify DC /,/-/p将打印包含Centrify DC和另一行包含-之间所有行。然而,它不能在一行内起作用。
你想要的是从该行中删除除版本号之外的所有内容。我建议你将版本号分组,并用它替换该行的所有内容:
$ echo "adcheck (CentrifyDC 4.4.3-421)" | sed 's/^.*[^0-9]\([0-9]*\.[0-9]*\.[0-9]*\).*$/\1/'
4.4.3

在这里,我们将版本号放在一个组中,格式为\([0-9]*\.[0-9]*\.[0-9]*\),并用该组替换所有行(通过引用\1)。
如果您的输入具有多个行,则可能需要一些隧道。
$ cat file
adcheck (CentrifyDC 4.4.3-421)
another line
still another line
$ sed 's/^.*[^0-9]\([0-9]*\.[0-9]*\.[0-9]*\).*$/\1/' file
4.4.3
another line
still another line

在这种情况下,向sed传递-n标志以抑制默认打印。然后,为s///命令提供一个地址(例如/adcheck (CentrifyDC /)以确保替换仅发生在与地址匹配的行中。最后,在s///命令中添加p标志 - 它将打印替换后的行:
$  sed -n '/adcheck (CentrifyDC /s/^.*[^0-9]\([0-9]*\.[0-9]*\.[0-9]*\).*$/\1/p' file
4.4.3

5
sed 's/[[:alpha:]|(|[:space:]]//g' | awk -F- '{print $1}' <<< "(CentrifyDC 4.4.3-421)"

输出:4.4.3

使用[:space:]去除额外的空格。

sed用于去除不需要的字符,awk -F-表示使用-作为字段分隔符。


1
括号表达式内部的管道符号是不必要的,因为括号表达式意味着“任何这些字符”。它可以是 sed 's/[[:alpha:]([:space:]]//g' - CJ Gaconnet
每次我们使用管道操作就会有小猫死亡。只用 awk 就足够了,不需要像 echo | sed | awk 这样复杂的操作。 - fedorqui

5

“你认为会成功的”修正版:

/usr/share/centrifydc/bin/adcheck --version | sed 's|.*CentrifyDC \([0-9\.]*\).*|\1|'

输出:

4.4.3

4

一行 脚本

perl -pe '($_)=/([0-9]+([.][0-9]+)+)/' YOURFILE.TXT

或者更长一点但可以处理多个版本:
perl -nle 'print $v if ($v)=/([0-9]+([.][0-9]+)+)/' YOURFILE.TXT

使用第一个命令行的示例

$> V=$(perl -pe '($_)=/([0-9]+([.][0-9]+)+)/'<<<'adcheck (CentrifyDC 4.4.3-421)')
$> echo "$V"
4.4.3

$> V=$(perl -pe '($_)=/([0-9]+([.][0-9]+)+)/' <<< 'dos2unix-8.2.3-beta.zip')
$> echo "$V"
8.2.3

$> echo 'A2 33. Z-0.1.2.3.4..5' | perl -pe '($_)=/([0-9]+([.][0-9]+)+)/'
0.1.2.3.4

$> gcc --version | perl -pe '($_)=/([0-9]+([.][0-9]+)+)/'
4.7.3

$> bash --version | perl -pe '($_)=/([0-9]+([.][0-9]+)+)/'
4.2.45

$> meld --version | perl -pe '($_)=/([0-9]+([.][0-9]+)+)/'
1.6.1

$> uname -a | perl -pe '($_)=/([0-9]+([.][0-9]+)+)/'
3.8.0

$> perl -pe '($_)=/([0-9]+([.][0-9]+)+)/' /etc/issue
13.04

注意: 第一条命令行提取的版本不包括最后的回车符(我指的是 \n)。如果这是一个问题,请使用第二个版本或将第一条命令行包装在 echo 中:

$> echo $( perl --version | perl -pe '($_)=/([0-9]+([.][0-9]+)+)/' )
5.14.2

很不幸,如果有多行包含版本号,这些版本号将被连接起来:
$> echo $(gwenview --version | perl -pe '($_)=/([0-9]+([.][0-9]+)+)/' )

4.8.44.10.54.10.4

为了每行提取一个版本,需要更改单行脚本:
perl -pe 'if(($_)=/([0-9]+([.][0-9]+)+)/){$_.="\n"}'

例子:
$> gwenview --version | perl -pe 'if(($_)=/([0-9]+([.][0-9]+)+)/){$_.="\n"}' 
4.8.4
4.10.5
4.10.4

为了仅提取第一个版本号并添加换行符(我是指新行\n),我建议:
perl -pe 'if(($v)=/([0-9]+([.][0-9]+)+)/){print"$v\n";exit}$_=""'

例子:

$> gwenview --version | perl -pe 'if(($v)=/([0-9]+([.][0-9]+)+)/){print"$v\n";exit}$_=""'
4.8.4

提供信息,我的 尝试不太好。谁知道如何使用 sed 获得与我的 perl 脚本相同的行为?

sed 's/\([0-9][0-9]*[.][0-9][0-9.]*\)/\n\1/'

如果您认为可以改进这些脚本,请随时发表评论 :)

2
这是我的解决方案
echo "adcheck (CentrifyDC 4.4.3-421)" | sed -nE "s/.*CentrifyDC (([0-9]+\.[0-9]+\.[0-9]+)-.*).*/\2"/p

让我对语法 (([0-9]+\.[0-9]+\.[0-9]+)-.*) 进行更详细的解释。
  1. 外部的圆括号将整个版本分为第一组,例如 4.4.3-421

  2. 然后内部的圆括号将连字符(-)前面的版本分为第二组,例如 4.4.3

希望这能帮到你!

1
这是一个Perl的解决方案:
echo "adcheck (CentrifyDC 4.4.3-421)" | perl -ne 'm/adcheck \(CentrifyDC (.*?)\)/; print "$1\n" '
/usr/share/centrifydc/bin/adcheck --version | perl -ne 'm/adcheck \(CentrifyDC (.*?)\)/; print "$1\n" '

1
另一种仅使用 awk 的方法:
$ echo "adcheck (CentrifyDC 4.4.3-421)" | awk '{sub(/-.*/,"",$3);print $3}'
4.4.3

...或者可能是cut的组合:

$ echo "adcheck (CentrifyDC 4.4.3-421)" | cut -d' ' -f3 | cut -d'-' -f1
4.4.3

0
例如,这个可以完成任务。
wget -V|head -n1|sed 's/[[:alpha:]|(|[:space:]]//g' | awk -F- '{print
> $1}'

与被接受的答案相比,这种方法有何不同?为什么某人可能更喜欢这种方法? - Jeremy Caney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接