Home > Mobile >  BASH: Remove leading and trailing zeroes from variable using pure bash
BASH: Remove leading and trailing zeroes from variable using pure bash

Time:08-13

Case Scenerio:

Variable or Array
var=( 002.20 20.020 20.002000 00200 20.02 .020)
for f in ${var[@]}; do echo ${f}; done
Output: 2.2 20.02 20.002 200 20.02 .02

Trying to achive this using pure bash that with help of $BASH_REMATCH capture groups

Tried: 
eg. 
f=20.0000210
[[ $f =~ ([0-9]?\.?0?[1-9]?)(0*$) ]]
echo ${BASH_REMATCH[@]}
210 21 0


Expected:
echo ${BASH_REMATCH[@]
20.000021 0

Can anyone help with this. Please. After debugging it seems bash capture groups are behaving unusually. I dont know how BASH_REMATCH works but from online tutorials i have seen that using () we can split string into BASH_REMATCH array. But something odd with splitting

oK after some debugging it appears unusual behaviour is due to cygwin bash. eg var=0002; echo ${var##0} or echo ${var## (0)} doesnt work as expected

CodePudding user response:

Another way: (Another Use Case: Below Method will help splitting a string based on delimeter)

var=( 002.20 20.020 20.002000 00200 20.02 .020)
for f in ${var[@]}; do 
[[ $f =~ (^[^\.?]*.)(.*) ]]; 
INT=$(echo ${BASH_REMATCH[1]}); 
FRAC=$(echo ${BASH_REMATCH[2]}); 
echo "$f --> ${INT## (0)}${FRAC%% (0)}"; done
Output
002.20 --> 2.2
20.020 --> 20.02
20.002000 --> 20.002
00200 --> 200
20.02 --> 20.02
.020 --> .02

Splits and captures the Integer part and Fractional Part

Capture 1 - (^[^.?].) --> Matches beginning to decimal point which is optional in case of natural numbers and append "." to result
Capture 2 - (.
) --> Fractional part

Using BASH_REMATCH[1] & [2], stores integer in INT and Fraction in FRAC

Using string expansion remove leading "0" from INT and trailing "0" from FRAC

CodePudding user response:

If you want to use [[ var =~ REGEX ]] and then BASH_REMATCH, you can do:

#!/bin/bash

var=( 002.20 20.020 20.002000 00200 20.02 .020)

for i in "${var[@]}"; do             # loop over each element in array
  if [[ $i =~ "." ]]; then           # does it contain '.'?
    [[ $i =~ ^0*(.*[^0] )0*$ ]]      # use regex to trim both ends
  else
    [[ $i =~ ^0*([^0] .*$) ]]        # otherwise trim from front.
  fi
  echo ${BASH_REMATCH[1]}            # output result
done

Example Output

2.2
20.02
20.002
200
20.02
.02

You can change echo as needed to output with printf for line control as desired.

CodePudding user response:

Using a regular expression approach in bash:

var=(002.20 20.020 20.002000 00200 20.02 .020 20.0000210)

# regex may match an empty string also
re='^0*([1-9][0-9]*)?(\.[0-9]*[1-9])?0*$'
for n in "${var[@]}"; do
   [[ $n =~ $re ]] && echo "$n => ${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
done

Output:

002.20 => 2.2
20.020 => 20.02
20.002000 => 20.002
00200 => 200
20.02 => 20.02
.020 => .02
20.0000210 => 20.000021

RegEx Demo and Details

RegEx Details:

  • ^: Start
  • 0*: Match 0 or more zeroes
  • ([1-9][0-9]*)?: Capture group #1 (optional) to match digit 1-9 followed by 0 or more of any digits
  • (\.[0-9]*[1-9])?: Capture group #2 (optional) to match dot then 0 or more of any digits then digit 1-9
  • 0*: Match 0 or more zeroes
  • $: End
  • In substitution we only keep values captured in capture group #1 and #2 ignoring leading and trailing zeroes.

CodePudding user response:

$ shopt -s extglob
$ var=( 002.20 20.020 20.002000 00200 20.02 .020 )
$ for f in "${var[@]## (0)}"; do
    [[ "$f" =~ \. ]] && f="${f%% (0)}"
    printf '%s\n' "$f"
  done
2.2
20.02
20.002
200
20.02
.02

CodePudding user response:

You can do it via sed.

$ var=( 002.20 20.020 20.002000 00200 20.02 .020)
$ for f in ${var[@]}; do echo $(echo $f|sed -r 's/^0 |0 $//g'); done
2.2
20.02
20.002
2
20.02
.02
  • Related