如果我有字符串:
geo:FR,主机:www.example.com
(实际上,字符串更复杂,并且具有更多字段。)
我想提取“ geo”值和“ host”值,当键的顺序更改时,我面临一个问题,如下所示:
host:www.example.com,geo:FR
我尝试了这一行:
sed 's/.\*geo:\([^ ]*\).\*host:\([^ ]*\).*/\1,\2/'
但是它仅适用于第一个字符串。 有没有办法在单个正则表达式中做到这一点,如果没有,最好的方法是什么?
答案 0 :(得分:2)
我建议使用单独的sed命令提取所需的每个文本:
s="geo:FR, host:www.example.com"
host="$(sed -n 's/.*host:\([^[:space:],]*\).*/\1/p' <<< "$s")"
geo="$(sed -n 's/.*geo:\([^[:space:],]*\).*/\1/p' <<< "$s")"
请参见online demo,echo "$host and $geo"
印刷品
www.example.com and FR
两个输入。
详细信息
-n
禁止行输出,p
打印匹配项.*
-将最后的0个字符与最后一个字符匹配... host:
-host:
子字符串,然后\([^[:space:],]*\)
-将除空格和逗号以外的任何0个或多个字符捕获到第1组中.*
-该行的其余部分。结果仅是第1组的内容(请参见替换模式中的\1
)。
答案 1 :(得分:2)
每当您在输入中包含标记/名称/值对时,我都会发现最好(最清晰,最简单,最可靠,最容易增强等)首先创建一个包含该映射的数组(f[]
如下),然后您只需按其标签访问值即可:
$ cat file
geo:FR, host:www.example.com
host:www.example.com, geo:FR
foo:bar, host:www.example.com, stuff:nonsense, badgeo:uhoh, geo:FR, nastygeo:wahwahwah
$ cat tst.awk
BEGIN { FS=":|, *"; OFS="," }
{
for (i=1; i<=NF; i+=2) {
f[$i] = $(i+1)
}
print f["geo"], f["host"]
}
$ awk -f tst.awk file
FR,www.example.com
FR,www.example.com
FR,www.example.com
以上内容可在每个UNIX盒的任何shell中使用任何awk进行工作。
答案 2 :(得分:0)
在这里,我已使用GNU Awk将分隔的key:value
对转换为有效的shell分配。使用Bash,您可以使用<(process substitution)
将这些分配加载到当前的shell中:
# source the file descriptor generated by proc sub
. < <(
# use comma-space as field separator, literal apostrophe as variable q
awk -F', ' -vq=\' '
# change every foo:bar in line to foo='bar' on its own line
{for(f=1;f<=NF;f++) print gensub(/:(.*)/, "=" q "\\1" q, 1, $f)}
# use here-string to load text; remove everything but first quote to use standard input
' <<< 'host:www.example.com, geo:FR'
)