Search code examples
regexbashshellsednested

How do I remove multiple bracket within nested bracket using sed?


I want to make a program editing file code with shell programming

there is command 'Remove ${} in arithmetic expansion$(())' and I have a problem in implementation.

I'm going to make bash shell code below

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

to

cnt=$(( cnt + cnt123 ))

I want to remove command substitution bracket in arithmetic Expansion bracket

I tried to do with this regex expression:

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

but, it just found a longest one.(even though there are another match before matched one)

if you want to see visualized regex expression, click this link visualized image

result showed like this:

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

How to do remove internal bracket in nested bracket? (I should just use awk or sed, but if it could be impossible, it doesn't matter using other bash command)


works example:

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

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

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

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


:my sample input file (it doesn't matter what it do for)

#! /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


Solution

  • As it is not an easy task for sed/awk regex and relevant functions, please let me show a perl solution, although perl is not tagged in your question.

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

    Input file example:

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

    Modified result:

    s=$(( s ** 2 ))
    sum=$(( a + b ))
    echo $(( (var * var2) / var3 ))
    echo ${d} $((t1 + t2)) ${e}
    
    • The perl substitution s/pattern/expression/e replaces the matched pattern with the perl expression instead of literal (or fixed) replacement. You can perform a dynamic replacement with this mechanism.
    • (?<=\$\(\().+?(?=\)) matches a substring which is preceded by $(( and followed )). Then the matched substring will be the content within $(( .. )). The perl variable $& is assigned to it.
    • The expression $_ = $&; s#\$\{(.+?)}#$1#g; $_ is a perl code to remove the paired ${ and } from the matched substring above. The g option after the delimiter # works as that of sed.