51

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?

Daniel Serodio
  • 1,123
  • 1
  • 9
  • 14
mtk
  • 26,802
  • 35
  • 91
  • 130
  • 10
    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

8 Answers8

63

use negative increment

seq -s, 10 -2 1
10,8,6,4,2
watael
  • 891
  • 6
  • 4
28

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

echo {10..1..2} | tr " " ,
10,8,6,4,2
Chris Down
  • 122,090
  • 24
  • 265
  • 262
  • 2
    That's short and quick, but I am on older bash version. – mtk Feb 15 '13 at 10:05
  • 23
    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 06:06
  • 1
    Why is it not portable? Do you have sources or proofs? I'm interested. – Benoit Duffez Sep 07 '15 at 07:50
15

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"
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
rush
  • 27,055
  • 7
  • 87
  • 112
7

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)

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
  • 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 'SO- stop being evil' 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 'SO- stop being evil' Feb 15 '13 at 22:30
  • @Gilles'SO-stopbeingevil', `printf` is not guaranteed to be builtin, and `echo` can't be used here unless you know the exact variant you have (POSIX without XSI leaves the behaviour unspecified if the first argument is `-n` or any argument contain backslashes). `s=$s,$i` and stripping the last `,` or not adding it on the first run would be an option yes. – Stéphane Chazelas Dec 02 '22 at 13:13
5

Try with:

   seq [OPTION]... FIRST INCREMENT LAST

Example:

$ seq 10 -1 1

jluna
  • 51
  • 1
  • 1
4

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
$
hlovdal
  • 651
  • 8
  • 11
1

I often loop over months and find the -w option useful (to preserve the two digits).

for i in $(seq -w 12 -1 01); do echo $i; done

I’m not sure why the -s, was used in the original reply

Miles
  • 13
  • 3
  • 1
    (1) You should always quote all shell variable references unless you have a good reason not to, and you’re *sure* you know what you’re doing.  So, in this example, you should say `echo "$i"`.  (2) Why not say just `seq -w 12 -1 01` ?  Why add the complexity of a shell loop? (See [Why is using a shell loop to process text considered bad practice?](https://unix.stackexchange.com/q/169716/80216))  (3) [watael’s answer](https://unix.stackexchange.com/a/64864/80216) uses  `-s,` because it is the short form of `--separator=","`, which is used in the question. … (Cont’d) – G-Man Says 'Reinstate Monica' Dec 02 '22 at 12:54
  • 1
    (Cont’d) …  (4) This (your post, above) isn’t really an answer to this question because it doesn’t say anything *relevant to what the question is asking* that isn’t already in [watael’s answer](https://unix.stackexchange.com/a/64864/80216). – G-Man Says 'Reinstate Monica' Dec 02 '22 at 12:55
0
for i in `seq 1 20 | sort -nr`; do echo $i; done
AdminBee
  • 21,637
  • 21
  • 47
  • 71
Tony Xu
  • 101
  • 3
  • (1) You should always quote all shell variable references unless you have a good reason not to, and you’re *sure* you know what you’re doing.  So, in this example, you should say `echo "$i"`.  (2) Why not say just ``seq 1 20 | sort –nr`` ?  Why add the complexity of a shell loop? (See [Why is using a shell loop to process text considered bad practice?](https://unix.stackexchange.com/q/169716/80216))  (3) `sort` is typically O(_N_  log _N_).  `tac`, as used in [hlovdal’s answer](https://unix.stackexchange.com/a/64975/80216), may be O(_N_), and therefore preferable. – G-Man Says 'Reinstate Monica' Dec 02 '22 at 12:20