so cal cheesehead
so cal cheesehead

Reputation: 2573

How to use sed to replace a command followed by 0 or more spaces in bash

I can't figure out how to replace a comma followed by 0 or more spaces in a bash variable. here's what i have:

base="test00 test01 test02 test03"
options="test04,test05, test06"

for b in $(echo $options | sed "s/, \+/ /g")
do
  base="${base} $b"
done

What i'm trying to do is append the "options" to the "base". Options is user input which can be empty or a csv list however that list can be

"test04, test05, test06" -> space after the comma

"test04,test05,test06" -> no spaces

"test04,test05, test06" -> mixture

what i need is my output "base" to be a space delimited list however no matter what i try my list keeps getting cut off after the first word.

My expected out is

"test00 test01 test02 test03 test04 test05 test06"

Upvotes: 1

Views: 65

Answers (2)

Charles Duffy
Charles Duffy

Reputation: 295855

If your goal is to generate a command, this technique is wrong altogether: As described in BashFAQ #50, command arguments should be stored in an array, not a whitespace-delimited string.

base=( test00 test01 test02 test03 )
IFS=', ' read -r -a options_array <<<"$options"

# ...and, to execute the result:
"${base[@]}" "${options_array[@]}"

That said, even this isn't adequate to many legitimate use cases: Consider what happens if you want to pass an option that contains literal whitespace -- for instance, running ./your-base-command "base argument with spaces" "second base argument" "option with spaces" "option with spaces" "second option with spaces". For that, you need something like the following:

base=( ./your-base-command "base argument with spaces" "second base argument" )
options="option with spaces, second option with spaces"

# read options into an array, splitting on commas
IFS=, read -r -a options_array <<<"$options"

# trim leading and trailing spaces from array elements
options_array=( "${options_array[@]% }" )
options_array=( "${options_array[@]# }" )

# ...and, to execute the result:
"${base[@]}" "${options_array[@]}"

Upvotes: 6

Mr. Llama
Mr. Llama

Reputation: 20919

No need for sed, bash has built in pattern substitution parameter expansion. With bash 3.0 or later, extglob added support for more advanced regular expressions.

# Enables extended regular expressions for +(pattern)
shopt -s extglob

# Replaces all comma-space runs with just a single space
options="${options//,+( )/ }"

If you don't have bash 3.0+ available or don't like enabling extglob, simply strip all spaces which will work most of the time:

# Remove all spaces
options="${options// /}"

# Then replace commas with spaces
options="${options//,/ }"

Upvotes: 4

Related Questions