0

I am trying to do multi condition check i.e., the input should not be empty and it should contain only numbers in while loop in Shell Script but i am facing multiple errors while trying to perform this operation. I have tried multiple options and i see multiple questions on this posted in Unix Stackexchange and Stack overflow but none of them helping that's why i am posting this question here Option 1:

while [ \( -z "$account_number" \) && \( "$account_number" =~ "^[0-9]+$" \) ];
do      printf 'Input account Number RWDEx: '
        read -r account_number
        [ -z "$account_number" ]  && echo 'Account Number cannot be empty; try again.'
done

This is throwing error [: missing `]' many suggested this error because of the space issue between condition and brackets but it didn't work

Option 2:

while [[ -z "$account_number" && "$account_number" =~ "^[0-9]+$" ]]
do      printf 'Input account Number RWDEx: '
        read -r account_number
        [ -z "$account_number" ]  && echo 'Account Number cannot be empty; try again.'
done

If i giving condition as above it not even asking for the input

Please help in solving this issue and i am using #!/bin/bash i tried even changing the script to /bin/bash instead of #!/bin/bash

2
  • There's no way $account_number can be both empty (-z) and (&&) match ^[0-9]+$. Your logic is flawed. Note that only the [ builtin of yash and zsh support a =~ operator. Sep 5, 2019 at 7:26
  • @StéphaneChazelas thanks for the reply can you help me how can i re frame this logic
    – Rahul
    Sep 5, 2019 at 7:28

1 Answer 1

2

Just use:

#! /bin/bash -
n=
pattern='^(0+|[123456789][0123456789]*)$' # decimal integer number,
                                          # exclude 0123 octals
until [[ $n =~ $pattern ]]; do
  IFS= read -rp 'Enter a decimal number: ' n || exit # exit upon EOF
done

Or:

#! /bin/bash -
pattern='^(0+|[123456789][0123456789]*)$' # decimal integer number,
                                          # exclude 0123 octals
while true; do
  IFS= read -rp 'Enter a decimal number: ' n || exit # exit upon EOF
  if [ -z "$n" ]; then
    echo >&2 "Cannot be empty, try again"
  elif [[ ! $n =~ $pattern ]]; then
    echo >&2 "Not a decimal integer number, try again"
  else
    break
  fi  
done

Or better, use the standard sh syntax, and then you don't even need bash:

#! /bin/sh -
while true; do
  printf >&2 'Enter a number: '
  IFS= read -r n || exit # exit upon EOF
  case $n in
    ("")
      echo >&2 "Cannot be empty, try again";;
    (*[!0123456789]* | 0*[!0]*)
      echo >&2 "Not a decimal integer number, try again";;
    (*)
      break;; # OK
  esac
done

Note that [ is a shell builtin. The [ of bash contrary to zsh or yash doesn't support a =~ operator.

Also, if you do [ x && y ], that's parsed as cmd1 arg && cmd2 arg2, so just runs [ x and if it's successful, run y ].

[[ ... ]] on the other hand is a special shell construct (from ksh) inside which && is also a form of and operator.

However, if you write:

[[ -z $var && $var =~ ^[0-9]+$ ]]

That's testing whether $var is both empty (-z) and matches ^[0-9]+$ which is not possible.

I think you meant:

[[ -z $var || ! $var =~ ^[0-9]+$ ]]

But even then the -z $var is redundant since if $var matches ^[0-9]+$ (one or more characters in the 0-9 range), it can't be empty.

Note that what [0-9] matches is more or less random in most locales on most systems, use [0123456789] if you want to match any decimal digits.

In shells like bash, it's generally a good idea to exclude numbers with leading zeros as they tend to be interpreted as octal numbers (where 010 means 8 for instance).

It's customary to issue user prompts on stderr (like bash's read -p does) as they are not part of the normal output of the command (the output your script produces if any and which you may for instance want to pipe to some other command).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .