Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I have iterate over numbers in various order. I am able to display them in increasing order, even with steps like:

$ seq --separator="," 1 10
1,2,3,4,5,6,7,8,9,10
$ seq --separator="," 1 2 10
1,3,5,7,9

I am also able to display them in reverse order, neither continuous nor step wise.

$ seq --separator="," 10 1   
$ seq --separator="," 10 2 1

No output for above commands.

My shell details:

$ bash --version
GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.

Let me know how I would be able to display the numbers in descending order?

share|improve this question
7  
For future readers, seq is a completely nonstandard tool and there is no guarantee that any two implementations will be the same. If you need to write a loop that iterates backwards over numbers in bash, use for ((i=$max;i>=0;i--)) … or the like. –  kojiro Feb 15 '13 at 13:13
    
@kojira Thanks for the info. Noted :) –  mtk Feb 15 '13 at 13:16
add comment

5 Answers

up vote 28 down vote accepted

use negative increment

seq -s, 10 -2 1
10,8,6,4,2
share|improve this answer
add comment

In general, you don't want to use seq, it's not portable (even among standard Linux environments). If you're using bash4+, you can use brace expansion:

echo {10..1..2} | tr " " ,
10,8,6,4,2
share|improve this answer
1  
That's short and quick, but I am on older bash version. –  mtk Feb 15 '13 at 10:05
17  
Sweet answer, but there's some irony when you point out seq is nonstandard and then use bash-4-only brace expansion. ;) –  kojiro Feb 15 '13 at 13:15
    
@kojiro - No argument to be honest ;-) My main concern is not one of whether the command exists (that may or may not matter depending on whether the script is being distributed/etc), but whether the command executes as is expected by the author. bash4's brace expansion almost has that guaranteed (if it works, it works as you expect), whereas seq doesn't. –  Chris Down Feb 16 '13 at 6:06
add comment

Another way in pure bash, ksh or zsh:

for ((i=10;i>0;i-=2)) ; do echo -n "$i," ; done

A pure POSIX sh way:

i=10
while [ "$i" -gt 2 ]; do printf "$i,"; i=$((i-2)); done
echo "$i"
share|improve this answer
1  
for's second expression should be the test and the third the step. –  manatwork Feb 15 '13 at 10:40
    
oh, thanks. fixed. –  rush Feb 15 '13 at 11:08
add comment

Now, standard POSIX ones:

awk 'BEGIN{for (i = 10; i > 0; i -= 2) print i}' | paste -sd, -

(interestingly, with mawk (and to a lesser extent gawk as well) a lot faster than GNU seq for i = 10000000 instead of i = 10)

Or

i=10; set --
while [ "$i" -gt 0 ]; do
  set -- "$@" "$i"
  i=$(($i - 2))
done
IFS=,
echo "$*"

(would only be more efficient with small numbers of iterations, especially with bash)

Or

echo 'for(i=10;i>0;i-=2) i' | bc | paste -sd, -

(which would support numbers of any size, but note that past a certain number of digits (numbers greater than 1070 in the POSIX locale at least), lines would be wrapped with backslashes)

share|improve this answer
1  
In GNU bc, you can avoid the line wrap by setting BC_LINE_LENGTH=0 in the environment. No such luck on other implementations. –  Gilles Feb 15 '13 at 22:26
1  
Why use the positional arguments rather than loop around s=$s,$i or call echo -n/echo \c/printf? –  Gilles Feb 15 '13 at 22:30
add comment

You can reverse the order using tac (cat in reverse). Even if seq should behave differently on various system, I think the following should be as portable as possible:

$ seq 1 10 | tr '\012' ',' | sed 's/,$//'; echo
1,2,3,4,5,6,7,8,9,10
$ seq 1 10 | tac | tr '\012' ',' | sed 's/,$//'; echo
10,9,8,7,6,5,4,3,2,1
$
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.