使用带有 pling/感叹号的 cut 作为分隔符

使用带有 pling/感叹号的 cut 作为分隔符

在 shell(不是 Bash)中,我有一个像这样的字符串,我想解析:

stringhere/morestring!99

解析后,我想保留99末尾的 ,并丢弃字符串的其余部分。

需要保留的子字符串并不总是两个字符长。它将是从 到!字符串末尾的一个或多个数字,或者是,

输入/输出示例:

In: stringhere/morestring!99
Out: 99

In: string/more!99,string/more!98,string/more!97
Out: 99

cut听起来像是显而易见的东西,除了!字符串中间的 。

是否有捷径可寻?会awk更好?

答案1

如果该字符串位于 FILE 中,并且您始终只需要第一个之后!和之前的第一个数字,,如果存在,则应该可以工作

awk -F'[!,]' '{print$2}' FILE

它采用!,作为分隔符并显示第二个字段,该字段将是 和 之间的第一个数字!,或紧随其后! ,如果该行中或之前没有。

,如果之前有第一个!上面的 awk 示例,则不适用。

您还可以将一个cut命令通过管道传输到另一个命令,首先指定!为分隔符并在第一个命令之后获取内容!,然后在第二个命令中指定,为分隔符并在第一个命令之前获取内容(,如果存在)

cut -d'!' -f2 FILE | cut -d',' -f1

答案2

您可以使用cut,但需要两次通过。第一个将获取第一个之后的内容!,第二个将删除之后的任何内容,

$ echo 'string/more!99,string/more!98,string/more!97' | 
    cut -d'!' -f2- | cut -d, -f1
99

同样,对于您没有的情况(这里不需要,第二个,我添加它只是为了表明您可以使用完全相同的命令):cut

$ echo 'string/more!99' | cut -d'!' -f2- | cut -d, -f1
99

另一种选择是sed

$ echo 'string/more!99,string/more!98,string/more!97' | 
    sed -E 's/^[^!]+!([0-9]+).*/\1/'
99
$ echo 'string/more!99' | sed -E 's/^[^!]+!([0-9]+).*/\1/'
99

或者perl

$ echo 'string/more!99,string/more!98,string/more!97' | 
    perl -pe 's/.+?!(\d+).*/\1/'
99
$ echo 'string/more!99' | perl -pe 's/.+?!(\d+).*/\1/'
99

或者GNUgrep

$ echo 'string/more!99,string/more!98,string/more!97' | 
    grep -oP '^[^!]+!\K\d+'
99
$ echo 'string/more!99' | grep -oP '^[^!]+!\K\d+'
99

答案3

您所需要的只是 shell 的参数扩展语法:这是在

$ input='stringhere/morestring!99'
$ echo "${input#*!}"
99

后面#跟着一个模式:最短 字首匹配该模式将被删除。

$ input='string/more!99,string/more!98,string/more!97'
$ first=${input%%,*}
$ echo "${first#*!}"
99

后面%%跟着一个模式:最长 后缀匹配的模式被删除。


${var#pattern)-- 删除最短匹配前缀。
${var##pattern)-- 删除最长匹配前缀。
${var%pattern)-- 删除最短匹配后缀。
${var%%pattern)-- 删除最长匹配后缀。

答案4

您也可以使用sed.使用 GNUsed并打开扩展正则表达式:

sed -E 's/^[^!]*!([0-9]+).*$/\1/'

或者 - 更便携:

sed 's/^[^!]*!\([0-9]\{1,\}\).*$/\1/p'

这将匹配模式“第一个之前的任何内容!,后跟一个或多个数字,之后可能是任何类型的字符,直到行尾”,并仅用“一个或多个数字”部分替换整行。

~> echo 'string/more!99,string/more!98,string/more!97' | sed -E 's/^[^!]*!([0-9]+).*$/\1/'
99

如果存在不匹配的行,您可以使用以下命令抑制它们

sed -nE 's/^[^!]*!([0-9]+).*$/\1/p'

反而。默认情况下,这不会输出任何内容,并且仅在找到匹配模式时才打印输出。

相关内容