'How to write a single line shell script with a while loop and if statement

I am trying to figure out the syntax for having a while loop and an if statement that checks for more than one condition, in a single-line shell script.

Executing something like this...

i=2; while [ $i -le 10 ]; do if [ $i -ne 3 -a $i -ne 5 ] echo $i " not equal to 3 or 5"; else echo $i; i=`expr $i + 1`; done

...I get the error

bash: syntax error near unexpected token `else'

On another hand if I remove the semicolon from between ...3 or 5" and else echo..., and try something like this...

i=2; while [ $i -le 10 ]; do if [ $i -ne 3 -a $i -ne 5 ] echo $i " not equal to 3 or 5" else echo $i; i=`expr $i + 1`; done

...then I get the error:

syntax error near unexpected token `done'

This is on an Ubuntu 14.04, in case it matters.

Am I perhaps missing some kind of a parenthesis somewhere, or is it something else?



Solution 1:[1]

This should work:

i=2; while [ $i -le 10 ]; do if [ $i -ne 3 -a $i -ne 5 ]; then echo $i " not equal to 3 or 5"; else echo $i; fi; i=`expr $i + 1`; done

and this should also work:

i=2; while [ $i -le 10 ]; do [ $i -ne 3 -a $i -ne 5 ] && echo "$i not equal to 3 or 5" || echo $i; i=$((i+1)); done

But I am not sure if it makes sense to write this in only one line

Solution 2:[2]

You still need a then, and a fi, and enough semicolons.

i=2; while [ $i -le 10 ]; do if [ $i -ne 3 -a $i -ne 5 ]; then echo "$i not equal to 3 or 5"; else echo $i; fi; i=$(expr $i + 1); done

The replacement of back-quotes `…` with $(…) is just a general good idea, not crucial to this discussion.

If written out conventionally on multiple lines (without semicolons), you'd have:

i=2
while [ $i -le 10 ]
do
    if [ $i -ne 3 -a $i -ne 5 ]
    then echo "$i not equal to 3 or 5"
    else echo $i
    fi
    i=$(expr $i + 1)
done

To convert that to a single line, you need a semicolon after each statement and condition:

i=2;
while [ $i -le 10 ];
do
    if [ $i -ne 3 -a $i -ne 5 ];
    then echo "$i not equal to 3 or 5";
    else echo $i;
    fi;
    i=$(expr $i + 1);
done

And now the white space (including newlines) can be replaced by single spaces on a single line.

And you could use i=$(($i + 1)) or even (in Bash) ((i++)) in place of expr, which avoids the use of the external command expr; the shell does the arithmetic internally.

I don't think there is a good reason to flatten the script onto one line.

Solution 3:[3]

Each if needs a then and fi:

i=2; while [ $i -le 10 ]; do if [ $i -ne 3 -a $i -ne 5 ] ; then echo $i " not equal to 3 or 5" ; else echo $i; i=`expr $i + 1`; fi ; done

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jonathan Leffler
Solution 2
Solution 3 choroba