1

Im beginner in shell scripting and im trying to achieve following , if i pass two numbers as argument for example = 0 5 , the console will output 1 2 3 4 5 , but if i pass 5 0 , console should output 5 4 3 2 1 , the first one works nice , but the second one does nothing in my script , it does not throw any arror.

script

if [[ $1 -lt $2 ]]; then
  for((i=$1;i<$2;i++))
  do
    if [[ "$i" -lt $2 ]]; then
      echo -n "$i "
    else 
      echo -n "$i"
    fi
  done
else
  for((i=$2;i>=$1;i--))
  do
    if [[ "$i" -gt $1 ]]; then
      echo -n "$i "
    else 
      echo -n "$i"
    fi
  done
fi

as i said the first condition works - numbers are 0 5 for example but the second when first number is greater than second does not . how can i fix it?

2
  • Wouldn't you expect the output 0 1 2 3 4 5 in the first case, and vice versa; or 4 3 2 1 0 in the second case? Commented Nov 5, 2015 at 11:47
  • A common idiom is to assign an empty value to the separator variable before the loop, then print it before the next value, then assign the separator to use for subsequent iterations of the loop. Commented Nov 5, 2015 at 11:49

4 Answers 4

3

You have a logical error in your second for loop:

for((i=$2;i>=$1;i--))
# should have been:
for((i=$1;i>=$2;i--))

If you exterminate your code you will see that $1 will always be bigger or equal than $2 in your else-statement:

if [[ $1 -lt $2 ]]; then
  # ...
else
  # now $1 is equal or bigger than $2

You properly want to change your if-statement as well:

if [[ "$i" -gt $1 ]]; then
# change to $2 because $i will never be bigger than $1
if [[ "$i" -gt $2 ]]; then

When all of this is said you should really consider using an existing tool like seq [fisrt] [increment] last:

seq 1 5 | xargs; # 1 2 3 4 5
seq 5 -1 1 | xargs; # 5 4 3 2 1
Sign up to request clarification or add additional context in comments.

1 Comment

Good answer, but I'm not so sure about the seq suggestion -- seq isn't POSIX-standardized; it's not guaranteed to exist on all systems that run bash, or to have any particular behavior on systems that do have it. Thus, I could see someone who wanted to write portable code very reasonably wanting to build a native replacement (though that could be written a fair sight better than it is here).
3

This will print "1 2 3 4 5" or "4 3 2 1 0" instead of "5 4 3 2 1", but I think that is a more reasonable output. If you want the non-symmetric output, it's easy enough to fix.

#!/bin/bash   

i=$1            
test $2 -gt $1 && op=+ || op=- 
while test $i != $2; do printf "%d " $(( i=$i $op 1)); done  
echo

Comments

1

There's no need for the nested ifs here -- it's more sensible to determine the test to use and the iteration detection beforehand, and then have only one loop that's always used:

#!/bin/bash

delta=${3:-1} # if $3 is given, treat it as number to increment/decrement by
if (( $1 < $2 )); then
  delta=$(( delta < 0 ? -delta : delta)); cmp=-lt
else
  delta=$(( delta > 0 ? -delta : delta)); cmp=-gt
fi

i=$1
while test "$i" "$cmp" "$2"; do
  printf '%s ' "$i"
  i=$(( i + $delta ))
done
printf '\n'

This has a great deal in common with the existing (excellent) answer by @William Pursell, but adds the ability to provide a skip value (for instance, to count from 0 to 100 by 10s) safely, which using an exact equality check doesn't do.

Comments

0

You can farm out some of the work to external tools:

if (( $1 > $2 )); then
    seq $1 -1 $(($2+1))
else
    seq $(($1+1)) 1 $2
fi | paste -sd " "

1 Comment

Boo, hiss re: assuming present of non-POSIX tools. :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.