Haris
Haris

Reputation: 12272

Regular expression for a string of numbers

Lets say I have a string of 4 numbers separated by space

1 4 16 28
# stored in $ids

So, to get the 4 number separately in four variables I was using

id1=$(echo $ids | sed -r "s/([0-9]+ ){0}([0-9]+) ?.*/\2/g")
id2=$(echo $ids | sed -r "s/([0-9]+ ){1}([0-9]+) ?.*/\2/g")
id3=$(echo $ids | sed -r "s/([0-9]+ ){2}([0-9]+) ?.*/\2/g")
id4=$(echo $ids | sed -r "s/([0-9]+ ){3}([0-9]+) ?.*/\2/g")

But the problem is, if the string has less then 4 numbers, the previous numbers are repeated.

For example, if the string was

1

then what we will get is

id1=1
id2=1
id3=1
id4=1

What I want is that, if there are less numbers, then the extra variables should have the value 0.

Is there a way to do that?

Note : I can only use sed

Upvotes: 1

Views: 110

Answers (3)

chepner
chepner

Reputation: 532428

You don't need sed. This will work in any POSIX-compatible shell:

read -r id1 id2 id3 id4 rest <<EOF
$ids 0 0 0 0
EOF

This will work for any number of values in ids. The line in the here document will contain at least 4 values, regardless of the value of ids, and any extra fields will be assigned to rest and can be ignored.

Upvotes: 0

James Brown
James Brown

Reputation: 37464

Try this regex instead, it returns "" if there is nothing to return:

$ echo 1 2 3 4 5 6|sed -r "s/^([0-9]+ *){0,3}//g;s/([0-9]+).*/\1/g;s/^$/0/g"
4
#                 change this latter value ^ 

$ echo 1 2 3|sed -r "s/^([0-9]+ *){0,3}//g;s/([0-9]+).*/\1/g;s/^$/0/g"
0
$

Upvotes: 1

Tom Fenech
Tom Fenech

Reputation: 74705

If you can use awk, you could try something like this:

$ awk 'function m(a) { return a ~ /^[0-9]+$/ ? a : 0 } 
  { print m($1), m($2), m($3), m($4) }'
1 4 16 281 # input
1 4 16 281
1          # input
1 0 0 0

The function tests whether the field contains one or more digits, replacing with 0 if it doesn't.

The best way to get the output into separate variables depends on what you plan on doing with them later and your shell version.

Using process substitution, you can do this:

str='1 4 16 281'
read -r id1 id2 id3 id4 < <(echo "$str" | awk '
  function m(a) { return a ~ /^[0-9]+$/ ? a : 0 } 
    { print m($1), m($2), m($3), m($4) }')

Less efficient but perhaps easier to understand would be to simplify the script and run it 4 times:

id1=$(echo "$str" | awk -v col=1 '{ print $col ~ /^[0-9]+$/ ? $col : 0 }')

Upvotes: 1

Related Questions