4

Hello I am trying to sort a set of numeric command line arguments and then echo them back out in reverse numeric order on the same line with a space between each. I have this loop:

for var in "$@"
do
echo -n "$var "
done | sort -rn

However when I added the -n to the echo the sort command stops working. I am trying to do this without using printf. Using the echo -n they do not sort and simply print in the order they were entered.

1
  • 1
    For what reason wouldn't you want to use printf? AFAIK, usually echo with arguments isn't portable. Commented Oct 9, 2013 at 14:25

8 Answers 8

3

You can do it like this:

a=( $@ )
b=( $(printf "%s\n" ${a[@]} | sort -rn) )

printf "%s\n" ${b[@]}
# b is reverse sorted nuemrically now
Sign up to request clarification or add additional context in comments.

Comments

3

To sort 3 2 1 use tr ' ' '\n' to split into lines, pipe it to sort and reassemble with xargs

echo 3 2 1 | tr ' ' '\n' | sort | xargs

Comments

1

man sort would tell you:

   sort - sort lines of text files

So you can transform the result into the desired format after sorting.

In order to achieve the desired result, you can say:

for var in "$@"
do
  echo "$var"
done | sort -rn | paste -sd' '

Comments

1

Maybe that's because sort is "line-oriented", so you need every number on a separate line, which is not the case using -n with echo. You could simply put the sorted numbers back in one line using sed, like that:

for var in "$@";
do
    echo "$var ";
done | sort -rn | sed -e ':a;N;s/\n/ /;ba'

1 Comment

Welcome to Stack Overflow. Yes, the trouble is because sort is line-oriented and the echo -n creates a single line. While the sed works, it is a fairly heavy duty option.
1

sort is used to sort multiple lines of text. Using the option -n of echo, you are printing everything in one line. If you want the output to be sorted, you have to print it in multiple lines :

for var in "$@"
do
    echo  $var
done | sort -rn

If you want the result on only one line you could do :

echo $(for var in "$@"; do echo $var; done | sort -rn)

7 Comments

echo -n doesn't display the \n
@Jite It's indeed a bit twisted to use the -e option in order to thwart the -n option.
Suggest $(...) in place of the back-ticks.
If you simply write echo $(...), everything will be on one line with a newline at the end. There's no need for the echo -n $(...) followed by echo to output the newline. You can also use printf "%s\n" "$@" | sort -rn as the command to remove the visible loop (the loop hides inside the printf command).
@HunterMcMillen As I wrote above, echo with options isn't portable. You seem to be right about bash, however in zsh as I use: echo -n Doesn't output the trailing newline. So adding echo -n "Bla\n" outputs the trailing newline. I prefer printf for this very reason.
|
1

One trick is to play with the IFS:

IFS=$'\n'
set "$*"
IFS=$' \n'
set $(sort -rn <<< "$*")
echo $*

This is the same idea but easier to read with the join() function:

join() {
    IFS=$1
    shift
    echo "$*"
}

join ' ' $(join $'\n' $* | sort -nr)

2 Comments

This works. I think you should explain a bit more about why it works, though. Is it intentional that you set the IFS to two non-standard settings, or was the second setting intended to restore the default? If the former, why not just IFS=$' '; if the latter, you've omitted tab and would do better to save the current value and restore it: save="$IFS"; IFS=$'\n';set "$*";IFS= "$save";set $(sort -rn <<< "$1"); echo $*. Since there is only one argument, you could write $1 instead of $* in the <<< redirect. Etc.
@Jonathan, the two IFS settings are intentional. The technique uses IFS and echo to join positional parameters with an arbitrary character. When IFS is set to $'\n' and set "$*" is called, the positional parameters are then delimited with newlines. I don't bother saving $IFS since it's only scoped to the sub shell: bash -c 'IFS="xyz" && printf "$IFS\n"'; printf "$IFS\n"
1

No loops required:

#!/bin/bash
sorted=( $(sort -rn < <(printf '%s\n' $@)) )
echo ${sorted[@]}

1 Comment

Most concise solution. I prefer this. One < is more than needed though.
0

Sorting numbers in single line either comma, or space seperated, use the below

 echo "12,12,3,55,567,23,6,9,35,423"|sed -e 's;[ |,];\n;g'|sort -n|xargs|sed -e 's; ;,;g'

if your output does not need comma, skip the sed after xargs

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.