2

I have a variable containing four numbers separated by a space, such as for instance:

a="12.3 423.4 11.0033 14.02"

But sometimes, I have a trailing whitespace:

a="12.3 423.4 11.0033 14.02 "

I want to replace the spaces with " & ", and for that, I do:

echo ${a// / & }

Which gives me:

12.3 & 423.4 & 11.0033 & 14.02

or if I have a trailing whitespace:

12.3 & 423.4 & 11.0033 & 14.02 & 

My problem is that I don't know if I'll have a space at the end of my string and I don't want that extra "&" in any case. What would be the most elegant way to avoid this extra character? Is there a way to say "replace if a space and the next character a digit"?

Edit: I knew I could use sed, but since there is a mechanism of variable substitution in bash, I would like to know how could I use it to do what I want. I don't know how to write "not end of line" or "is a digit" in the bash substitution.

Maxime Chéramy
  • 17,761
  • 8
  • 54
  • 75

5 Answers5

9

This will remove trailing space if there is any:

a=${a% }

Then you can do your replace:

a=${a// / & }
danadam
  • 3,350
  • 20
  • 18
  • Thank you, I will use `${${a% }// / & }` unless someone comes with a better idea. I'll pick the best answer later. *Edit:* hum, bash says bad substitution while it's fine for zsh... I need to do it in 2 steps as you did. – Maxime Chéramy Sep 27 '13 at 14:05
1

You could use sed and capture the match.

$ echo 12.3 423.4 11.0033 14.02 | sed 's/ [0-9]/ \&&/g'
12.3 & 423.4 & 11.0033 & 14.02

So with the / [0-9]/ you're only replacing where there is a space followed by a number.

If you didn't want to use sed you could check that the next character isn't EOL.

${a// [^$]/ & }
ben_re
  • 518
  • 2
  • 12
1
shopt -s extglob            # enable extended globbing patterns
b=${a/%+([[:blank:]])/}     # remove trailing whitespace
b=${b/#+([[:blank:]])/}     # remove leading whitespace
b=${b//+([[:blank:]])/ & }  # globally replace whitespace by " & "
echo ">$a<"
echo ">$b<"
>12.3 423.4 11.0033 14.02 <
>12.3 & 423.4 & 11.0033 & 14.02<

references:

http://www.gnu.org/software/bash/manual/bashref.html#Pattern-Matching
http://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
1

This is probably a contrived approach, but FWIW. If you are ok with multiple consecutive spaces being replaced with a single &, you could use bash read and printf built-ins to split the string into a array (assuming default whitespace IFS for the split) and then join back using a temporary IFS of &, see below.

a="12.3 423.4 11.0033 14.02 "
read -r -a x <<< "${a}"
IFS='&' eval 'printf -v a "%s" "${x[*]}"'
echo $a
12.3&423.4&11.0033&14.02
iruvar
  • 22,736
  • 7
  • 53
  • 82
0

Maybe you could just do

a=`echo "12.3 423.4 11.0033 14.02 " | sed 's/ *$//'`
echo ${a// / & }

That way you're removing the trailing whitespaces.

jlhonora
  • 10,179
  • 10
  • 46
  • 70