使用 sed 时转义“./”

Posted

技术标签:

【中文标题】使用 sed 时转义“./”【英文标题】:Escape "./" when using sed 【发布时间】:2021-12-10 14:06:55 【问题描述】:

我想使用 grep 通过管道从 $lastblock 中排除单词,但我发现 grep 仅适用于文件,不适用于 stdout 输出。

所以,这就是我正在使用的:

lastblock="./2.json"
echo $lastblock | sed '1,/firstmatch/d;/.json/,$d'

我想排除 ./.json,只保留两者之间的内容。 此 sed 命令对于此目的是正确的,但是如何转义 ./ 替换 firstmatch 以便它可以工作? 提前致谢!

【问题讨论】:

【参考方案1】:

使用 bash 的Parameter Substitution

lastblock="./2.json"
name="$lastblock##*/" # strips from the beginning until last / -> 2.json
base="$name%.*"       # strips from the last . to the end      -> 2

【讨论】:

从技术上讲,P.E. 不仅仅是 bash,它也是 POSIX 定义/要求的。【参考方案2】:

但我发现 grep 仅适用于文件,不适用于标准输出。

在这里。 (如果您的 grep 支持 -P 标志。

lastblock="./2.json"
echo "$lastblock" | grep -Po '(?<=\./).*(?=\.)'

但是如何逃避./

对于sed(1),使用反斜杠\对其进行转义

lastblock="./2.json"
echo "$lastblock" | sed 's/^\.\///;s/\..*$//'

或者使用不同的分隔符,比如管道|

sed 's|^\./||;s|\..*$||'

awk

lastblock="./2.json"
echo "$lastblock" | awk -F'[./]+' 'print $2'

bashv3开始,正则表达式模式匹配支持使用[[ ... ]]关键字内的=~运算符。

lastblock="./2.json"
regex='^\./([[:digit:]]+)\.json'
[[ $lastblock =~ $regex ]] && echo "$BASH_REMATCH[1]"

虽然 P.E. 应该足以满足此目的。

【讨论】:

【参考方案3】:

我想使用 grep 通过管道从 $lastblock 中排除单词,但我发现 grep 仅适用于文件,不适用于 stdout 输出。

废话。 grep 对同一个输入的作用相同,无论是来自文件还是来自标准输入。

所以,这就是我正在使用的:

lastblock="./2.json"
echo $lastblock | sed '1,/firstmatch/d;/.json/,$d'

我想排除 ./ 和 .json,只保留两者之间的内容。这个 sed 命令对于这个目的是正确的,

对于所述目的,该 sed 命令远非正确。它有这样的效果:

删除从第一行到下一个匹配正则表达式/firstmatch/ 的每一行,AND 删除从第一个匹配正则表达式/.json/ 到最后一个文件的每一行(注意. 是一个正则表达式元字符)。

要删除部分行而不是删除整行,请使用s/// 命令而不是d 命令。至于转义,您可以通过在字符前面加上反斜杠 (\) 将字符转义为 sed,它本身必须被引用或转义以保护它不被 shell 解释。此外,大多数正则表达式元字符在出现在字符类中时都会失去其特殊意义,我发现这是将它们作为文字包含在模式中的一种更清晰的方式。例如:

lastblock="./2.json"
echo "$lastblock" | sed 's/^[.]\///; s/[.]json$//'

也就是说要删除出现在(任何)行开头的文字字符./,并分别删除出现在行尾的文字字符.json

或者,如果您只想修改./开头并以.json结尾的行,那么您可以使用带有捕获组和反向引用的单个s命令:

lastblock="./2.json"
echo "$lastblock" | sed 's/^[.]\/\(.*\)[.]json$/\1/'

也就是说,在以./ 开头并以.json 结尾的行上,捕获这两者之间的所有内容,并将整行替换为仅捕获的部分。

【讨论】:

【参考方案4】:

当您想避免使用斜线时,可以使用其他字符,例如“#”。 您可以记住匹配的部分并在替换中使用它。 使用[.] 避免点为任何字符。

echo "$lastblock" | sed -r 's#[.]/(.*)[.]json#\1#'

【讨论】:

【参考方案5】:

解决方案!

感谢this legendary, unrelated answer,今天才发现tr 命令。

在 Google 上搜索如何排除“.”时和“/”,100% 的 *** 答案都没有帮助。

因此,要从命令输出中转义字符,只需附加此管道:

| tr -d "character-emoji-anything-you-want-to-exclude"

所以,一个完整且简单的示例:

echo "./2.json" | tr -d "/" | tr -d "." | tr -d "json"

完成了!

【讨论】:

非常感谢@sorpigal

以上是关于使用 sed 时转义“./”的主要内容,如果未能解决你的问题,请参考以下文章

sed命令反斜杠的转义

Sed命令中含有转义字符的解决方法

Sed命令中含有转义字符的解决方法

如何使用 unix 实用程序 (sed/tr/awk) 用非转义等效项替换所有转义序列

shell脚本之sed使用----替换变量转义字符

为 sed 替换模式转义字符串