简体   繁体   中英

Bash Replace String in a variable using regex

I am trying to replace a string in a variable using regex. However as soon as I use regex it's not working.

Source String:

The number could be anything, any valid integer.

message='"autotermination_minutes": 15,'

Expected String

   message='"autotermination_minutes": 30,'

Following is working (without regex)

echo ${message/'"autotermination_minutes": 15'/'"autotermination_minutes": 30'}

Following doesn't work (with Regex)

echo ${message/'"autotermination_minutes": '[0-9]/'"autotermination_minutes": 30'}

it shows, following output

"autotermination_minutes": 305,

[0-9] only matches a single digit.

Use [0-9][0-9] to match two:

➜ echo ${message/'"autotermination_minutes": '[0-9][0-9]/'"autotermination_minutes": 30'}
"autotermination_minutes": 30,

Note that Bash parameter substitutions are very limited in functionality. What you're doing here doesn't even have anything to do with regular expressions—these patterns are just globs. So, instead of a [0-9]+ that you'd expect from a regex, you need to use +([0-9]) to match one or more digits:

➜ shopt -s extglob
➜ echo ${message/'"autotermination_minutes": '+([0-9])/'"autotermination_minutes": 30'}
"autotermination_minutes": 15,

See also here .

But you really should be using sed or perl :

➜ echo "$message" | sed -E 's/[0-9]+/30/'
"autotermination_minutes": 30,

Or, if your input is JSON, you really should be using a JSON parser and read/write the file properly rather than using regular expressions.

In pure bash, there is no way to capture a value from original string and have it back in replacement using a back-reference.

You may use a simple sed here with a capture group and back-reference:

message='"autotermination_minutes": 15,'
sed -E 's/("autotermination_minutes": *)[0-9]+/\130/' <<< "$message"

"autotermination_minutes": 30,

How about a bash-only solution:

message='"autotermination_minutes": 15,'
pattern='(.*autotermination_minutes":[[:blank:]]*)([[:digit:]]+)(.*)'
replacement='30'

if [[ $message =~ $pattern ]]; then
    echo "${BASH_REMATCH[1]}${replacement}${BASH_REMATCH[3]}"
else
    echo "$message"
fi

Note that it is less efficient in both code size and execution time than properly designed sed or awk solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM