sed 用管道和星星替换字符串
sed replace string with pipe and stars
我有以下字符串:
|**barak**.version|2001.0132012031539|
在文件 text.txt
中。
我想用以下内容替换它:
|**barak**.version|2001.01.2012031541|
所以我运行:
sed -i "s/\|\*\*$module\*\*.version\|2001.0132012031539/|**$module**.version|$version/" text.txt
但结果是重复的而不是替换:
|**barak**.version|2001.01.2012031541|**barak**.version|2001.0132012031539|
我做错了什么?
这是模块和版本的值:
$ echo $module
barak
$ echo $version
2001.01.2012031541
假设:
- 感兴趣的行以管道 (
|
) 开始和结束,并且在数据中间的某处还有一个管道
- 搜索仅基于数据中第一个/第二个管道之间存在的
${module}
的值
- 我们不知道第一个/第二个管道之间还有什么
- 版本号是第二个/第三个管道之间唯一的东西
- 我们不知道要替换的版本号
示例数据:
$ module='barak'
$ version='2001.01.2012031541'
$ cat text.txt
**barak**.version|2001.0132012031539| <<<=== leave this one alone
|**apple**.version|2001.0132012031539|
|**barak**.version|2001.0132012031539| <<<=== replace this one
|**chuck**.version|2001.0132012031539|
|**barak**.peanuts|2001.0132012031539| <<<=== replace this one
一个 sed
解决方案启用了 -E
xtended regex 支持并使用捕获组:
$ sed -E "s/^(\|[^|]*${module}[^|]*).*/|${version}|/" text.txt
其中:
\|
- 第一次出现(转义管道)告诉 sed
我们正在处理文字管道;后续管道将被视为文字字符串
^(\|[^|]*${module}[^|]*)
- 第一个捕获组从行首开始,以竖线开始,然后是一些非竖线字符,然后是搜索模式 (${module}
),然后更多非管道字符(继续到下一个管道字符)
.*
- 匹配行的其余部分(我们将丢弃)
|${version}|
- 用我们的第一个捕获组替换行,然后是管道,然后是新的替换值 (${version}
),最后是管道
以上生成:
**barak**.version|2001.0132012031539|
|**apple**.version|2001.0132012031539|
|**barak**.version|2001.01.2012031541| <<<=== replaced
|**chuck**.version|2001.0132012031539|
|**barak**.peanuts|2001.01.2012031541| <<<=== replaced
使用 GNU awk 的 awk 替代方案:
awk -v mod="$module" -v vers="$version" -F \| '{ OFS=FS;split(,map,".");inmod=substr(map[1],3,length(map[1])-4);if (inmod==mod) { =vers } }1' file
使用 $module 和 $version 将两个变量 mod 和 vers 传递给 awk。将字段分隔符设置为 |。使用 split 函数将第二个字段拆分为数组映射并使用 .作为分隔符。然后使用 substr 函数从数组的第一个索引中去除前导和结尾“**”,以将 module 名称公开为 mod。将其与 mod 变量进行比较,如果匹配,则将第三个分隔字段更改为变量 vers。用简写 1
打印行
管道仅在您使用 扩展 正则表达式时才特殊:sed -E
没有理由在这里需要扩展,坚持使用基本的正则表达式:
sed "
# for lines matching module.version
/|\*\*$module\*\*.version|/ {
# replace the version
s/|2001.0132012031539|/|$version|/
}
" text.txt
或者作为一个不可读的单行
sed "/|\*\*$module\*\*.version|/ s/|2001.0132012031539|/|$version|/" text.txt
我有以下字符串:
|**barak**.version|2001.0132012031539|
在文件 text.txt
中。
我想用以下内容替换它:
|**barak**.version|2001.01.2012031541|
所以我运行:
sed -i "s/\|\*\*$module\*\*.version\|2001.0132012031539/|**$module**.version|$version/" text.txt
但结果是重复的而不是替换:
|**barak**.version|2001.01.2012031541|**barak**.version|2001.0132012031539|
我做错了什么? 这是模块和版本的值:
$ echo $module
barak
$ echo $version
2001.01.2012031541
假设:
- 感兴趣的行以管道 (
|
) 开始和结束,并且在数据中间的某处还有一个管道 - 搜索仅基于数据中第一个/第二个管道之间存在的
${module}
的值 - 我们不知道第一个/第二个管道之间还有什么
- 版本号是第二个/第三个管道之间唯一的东西
- 我们不知道要替换的版本号
示例数据:
$ module='barak'
$ version='2001.01.2012031541'
$ cat text.txt
**barak**.version|2001.0132012031539| <<<=== leave this one alone
|**apple**.version|2001.0132012031539|
|**barak**.version|2001.0132012031539| <<<=== replace this one
|**chuck**.version|2001.0132012031539|
|**barak**.peanuts|2001.0132012031539| <<<=== replace this one
一个 sed
解决方案启用了 -E
xtended regex 支持并使用捕获组:
$ sed -E "s/^(\|[^|]*${module}[^|]*).*/|${version}|/" text.txt
其中:
\|
- 第一次出现(转义管道)告诉sed
我们正在处理文字管道;后续管道将被视为文字字符串^(\|[^|]*${module}[^|]*)
- 第一个捕获组从行首开始,以竖线开始,然后是一些非竖线字符,然后是搜索模式 (${module}
),然后更多非管道字符(继续到下一个管道字符).*
- 匹配行的其余部分(我们将丢弃)|${version}|
- 用我们的第一个捕获组替换行,然后是管道,然后是新的替换值 (${version}
),最后是管道
以上生成:
**barak**.version|2001.0132012031539|
|**apple**.version|2001.0132012031539|
|**barak**.version|2001.01.2012031541| <<<=== replaced
|**chuck**.version|2001.0132012031539|
|**barak**.peanuts|2001.01.2012031541| <<<=== replaced
使用 GNU awk 的 awk 替代方案:
awk -v mod="$module" -v vers="$version" -F \| '{ OFS=FS;split(,map,".");inmod=substr(map[1],3,length(map[1])-4);if (inmod==mod) { =vers } }1' file
使用 $module 和 $version 将两个变量 mod 和 vers 传递给 awk。将字段分隔符设置为 |。使用 split 函数将第二个字段拆分为数组映射并使用 .作为分隔符。然后使用 substr 函数从数组的第一个索引中去除前导和结尾“**”,以将 module 名称公开为 mod。将其与 mod 变量进行比较,如果匹配,则将第三个分隔字段更改为变量 vers。用简写 1
打印行管道仅在您使用 扩展 正则表达式时才特殊:sed -E
没有理由在这里需要扩展,坚持使用基本的正则表达式:
sed "
# for lines matching module.version
/|\*\*$module\*\*.version|/ {
# replace the version
s/|2001.0132012031539|/|$version|/
}
" text.txt
或者作为一个不可读的单行
sed "/|\*\*$module\*\*.version|/ s/|2001.0132012031539|/|$version|/" text.txt