![如何在 Linux 和 Mac 之间使用跨平台/标准 sed?](https://linux22.com/image/205020/%E5%A6%82%E4%BD%95%E5%9C%A8%20Linux%20%E5%92%8C%20Mac%20%E4%B9%8B%E9%97%B4%E4%BD%BF%E7%94%A8%E8%B7%A8%E5%B9%B3%E5%8F%B0%2F%E6%A0%87%E5%87%86%20sed%EF%BC%9F.png)
您好,我有一个脚本在 makefile 中运行以进行项目部署。我在其中使用 sed 从输入字符串中捕获环境和项目名称,并且在 ubuntu 中效果很好。
这个简单的命令
echo deploy-api-production | sed -E 's/deploy-\w+-(\w+)/\1/'
production
在 ubuntu 中给出了预期结果
ubuntu执行
$ echo deploy-api-production | sed -E 's/deploy-\w+-(\w+)/\1/'
production
但在 mac 中给出了整个完整的字符串deploy-api-production
mac执行:
$ echo deploy-api-production | sed -E 's/deploy-\w+-(\w+)/\1/'
deploy-api-production
是否有某种统一的 sed 以便我在 mac 中也能得到相同的结果?
我希望输出也只是 mac 执行中的生产
情况 2 - 更通用,也包括前缀
想要正确解析这个
echo a-deploy-api-production | someprocessing
production
so 与上面的情况类似,但是a-
在该单词之前多了一个前缀单词deploy
我尝试了类似于当前给定解决方案的方法,但没有成功
echo a-deploy-api-production | awk -F'-' '$1=="a-deploy"{print $3}'
上面的结果为空,想要修改以获得结果production
答案1
您可以使用awk
:
echo deploy-api-production | awk -F'-' '$1=="deploy"{print $3}'
这会将文本分割成由 分隔的部分-
。它要求第一个字段与单词匹配deploy
,然后打印第三个字段。
在您更新的问题中,您包含了一个新的变体。您不能使用相同的awk
代码直接比较,a-deploy
因为这是两个字段(请记住,它们被破折号分隔),并且$1
只是第一个字段(即,a
而不是deploy
在这个新实例中)。
在不了解所有用例的情况下,我建议您可能更乐意搜索deploy
字符串中的任何位置,如果找到,则打印最后一个字段。 (这也适用于您的原始案例。)
echo deploy-api-production | awk -F'-' '/deploy/ {print $NF}'
production
echo a-deploy-api-production | awk -F'-' '/deploy/ {print $NF}'
production
答案2
使用 POSIX-莱 sed
,两种场景都可以获得所需的结果,如图所示:
w='[[:alpha:]][_[:alnum:]]*'
echo 'deploy-api-productionN' |
sed -n -e "/^\($w-\)\{0,1\}deploy-/s/^$w\(-\($w\)\)\{1,\}\$/\2/p"
观察结果:
- 由于 sed 没有单词的符号,我们将为它构建一个正则表达式并将它们存储在 shell 变量中$w
- \{0,1\} 是 BRE 的 ?
- \{1,\} 是 + 的 BRE
- \(...\) 是 (...) 的 BRE
答案3
您在两个系统上得到不同的结果,因为 GNU 系统使用正则表达式库,该库已扩展为包含来自称为PCRE
(Perl 兼容的正则表达式)。这些符号(如\s
和\w
)不是标准符号,并且不受sed
所有系统支持(通常不在 GNU 系统之外)。
-
如果行以子字符串deploy
或开头,您似乎想在最后一个(破折号)之后输出行的最后一部分something-deploy
。
您可以使用标准方法来做到这sed
一点
sed '/^deploy/ s/.*-//'
或与
sed '/^something-deploy/ s/.*-//'
如果前面的正则表达式与当前输入行匹配,这些sed
表达式将触发替换。s/.*-//
此替换会删除该行中直到并包括最后一个破折号的所有内容。
在这种情况下,如果需要,可以将触发表达式与替换结合起来:
sed 's/^deploy.*-//'
sed 's/^something-deploy.*-//'
如果您的数据不是由echo
(如问题中所示)输出的静态字符串,而是变量中的某个值,那么让 shell 执行此操作而不是调用外部程序会更有效:
string=deploy-api-production
if [[ $string == deploy-* ]]; then
printf '%s\n' "${string##*-}"
fi
您将使用变量赋值,而不是printf
如果您想保留修改后的值,如 中所示new=${string##*-}
。
扩展将从与 shell 模式匹配的${variable##pattern}
最长前缀字符串中删除。$variable
pattern