【问题标题】:How do I remove multiple bracket within nested bracket using sed?如何使用 sed 删除嵌套括号内的多个括号?
【发布时间】:2022-10-19 22:46:06
【问题描述】:

我想用shell编程制作一个程序编辑文件代码

有命令'在算术扩展 $(()) 中删除 ${}'我在实施中有问题。

我将在下面制作 bash shell 代码

cnt=$(( ${cnt} + ${cnt123} ))

cnt=$(( cnt + cnt123 ))

我想删除算术扩展括号中的命令替换括号

我尝试使用这个正则表达式:

sed -Ei 's/(\$\(\()([^\)]*?)\$\{([^\}]+?)\}(.*?)(\)\))/\1\2\3\4\5/g' $file

但是,它只是找到了一个最长的。(即使在匹配之前还有另一个匹配)

如果您想查看可视化的正则表达式,请单击此链接visualized image

结果显示如下:

cnt=$(( ${cnt} + cnt123 ))

如何删除嵌套括号中的内部括号? (我应该只使用 awk 或 sed,但如果不可能,使用其他 bash 命令也没关系)


作品示例:

s=$(( ${s} ** 2 ))s=$(( s ** 2 ))

sum=$(( ${a} + ${b} ))sum=$(( a + b ))

echo $(( (${var} * ${var2}) / ${var3} ))echo $(( (var * var2) / var3 ))

echo ${d} $((${t1} + ${t2})) ${e}echo ${d} $(( t1 + t2 )) ${e}


:我的示例输入文件(不管它做什么)

#! /bin/bash

cnt=0
cnt123=1
for filename in *
do
        fname=$(basename $filename)
        cname=$(echo $fname | tr A-Z a-z)
        if [ "$fname" !=  "$cname" ] 
        then
                if [ -e "$cname" ]
                then 
                   echo "$cname already exists"
                   exit 1
                fi
                echo "$fname is renamed $cname"
                mv $fname $cname
                cnt=$(( ${cnt}+ ${cnt123} ))
        fi
done
echo "Total count: $cnt"
exit 0

【问题讨论】:

  • 对于How to do remove internal bracket in nested bracket? (I should just use awk or sed),请为此添加一些样本,以便也可以在这些样本上测试答案,干杯。
  • 找到一个合适的解析器并使用它。这不是 sed 或 awk 的工作
  • @oguzismail 那么,您建议使用什么命令进行解析?

标签: regex bash shell sed nested


【解决方案1】:

由于 sed/awk 正则表达式和相关功能不是一件容易的事, 请让我展示一个perl 解决方案,尽管perl 未标记 你的问题。

perl -i -pe 's/(?<=$(().+?(?=)))/ $_ = $&; s#${(.+?)}#$1#g; $_ /ge' "$file"

输入文件示例:

s=$(( ${s} ** 2 ))
sum=$(( ${a} + ${b} ))
echo $(( (${var} * ${var2}) / ${var3} ))
echo ${d} $((${t1} + ${t2})) ${e}

修改结果:

s=$(( s ** 2 ))
sum=$(( a + b ))
echo $(( (var * var2) / var3 ))
echo ${d} $((t1 + t2)) ${e}
  • perl 替换 s/pattern/expression/e 替换匹配的 pattern 使用 perl expression 而不是文字(或固定) 替代品。您可以使用此机制执行动态替换。
  • (?&lt;=$(().+?(?=)) 匹配前面有 $(( 的子字符串 并关注))。然后匹配的子字符串将是其中的内容 $(( .. ))。 perl 变量$&amp; 分配给它。
  • 表达式 $_ = $&amp;; s#${(.+?)}#$1#g; $_ 是要删除的 perl 代码 来自上面匹配的子字符串的配对 ${}g 选项 在分隔符 # 之后,与 sed 的分隔符相同。

【讨论】:

  • 有趣的方法! @SeungYunBaek 捕获嵌套括号的扩展想法,使用 recursive regex 就像 this demo at tio.run
  • 谢谢您的回答。我有一个问题问你。你用 Perl 来解决这个问题。但它看起来像不同的表达。我不擅长语法,我第一次看到 Perl,所以我可能会误导。为什么它们使用相同的正则表达式彼此不同?有一种不同版本的正则表达式? .
  • @bobblebubble 谢谢你的提议!它可能适用于我的问题。
  • @SeungYunBaek 谢谢你的回复。有一些regex 变体称为flavors。典型的有BRE(基本正则表达式)、ERE(扩展正则表达式)和PCRE(Perl 兼容正则表达式)按历史顺序排列。而sedawk 最多支持EREPerlpython 和其他现代语言支持PCRE,它具有更多功能,例如环视断言、递归正则表达式和动词。
  • 例如,(?&lt;=$(() 是一个后向断言,它匹配前导 $((,但匹配的子字符串不包含在捕获组中。仅提取基本子字符串(不包括前导/尾随子模式)很有用。
【解决方案2】:

根据上下文,您可能希望将匹配范围限制为仅字母数字字符

sed -Ei.bak 's/${([[:alnum:]]+)}//g'

以避免无意中匹配其他内容。

【讨论】:

  • 感谢您的回答,但我想删除算术扩展中的命令扩展,而不是全部。
【解决方案3】:

使用sed

$ sed -Ei.bak 's/${([^}]*)}//g' input_file
cnt=$(( cnt + cnt123 ))

【讨论】:

  • 感谢您的回答,但我也想删除 '$' 字符并在 shell 代码中保留另一个 '{ }' 括号
  • @백승윤 对不起,我错过了,请检查编辑
  • 对不起,但这对我的问题不起作用。它也删除了命令替换,而不是算术扩展。我想在算术扩展中保留命令替换。谢谢。
【解决方案4】:
printf="cnt=$(( ${cnt} + ${cnt123} ))" | tr -d '{' | tr -d '}'

我在这里使用 printf 是因为它比 echo 稍微可信一些。确保你转义 $,否则你会因为 bash 试图解释变量而得到一个错误。

【讨论】:

    猜你喜欢
    • 2019-08-11
    • 2020-02-14
    • 2011-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-24
    相关资源
    最近更新 更多