29

How can I rearrange all of the lines in a file from longest to shortest? For e.g.:

elephant
zoo
penguin

Would be changed to

elephant
penguin
zoo
Zombo
  • 1
  • 62
  • 391
  • 407
Village
  • 22,513
  • 46
  • 122
  • 163
  • The example is a bit misleading, if you don't go back to read the question. To sort list of words, longest to shortest, adapt the acceptable answer e.g. `pip search json |awk '{print length($1)"\t"$1}' |sort -rn |cut -d' ' -f2-`. Obviously "pip search json" is just there to produce output instead of a filename. – ILMostro_7 Mar 28 '17 at 10:40

4 Answers4

57

Add the line length as the first field of the line, sort, and remove the line length:

awk '{ print length($0) " " $0; }' $file | sort -r -n | cut -d ' ' -f 2-
thiton
  • 35,651
  • 4
  • 70
  • 100
  • 2
    why the cat? [UUoCA](http://partmaps.org/era/unix/award.html) – Fredrik Pihl Nov 28 '11 at 13:44
  • 1
    @Fredrik: I like to have the filename in front of my pipelines. You have the nicer award, though, so I have fixed it. – thiton Nov 28 '11 at 13:47
  • 1
    can be shortened to `$ awk '{print length"\t"$0}' File | sort -rn | cut -f2-` which is basically the same thing except that cut operates on tabs per default so ignore this :-) – Fredrik Pihl Nov 28 '11 at 13:50
  • @Fredrik Your shorter version that uses tabs as delimiter instead of the space character has the negative side effect that the tab is printed first. Command `$ awk '{print length"\t"$0}' tlds-alpha-by-domain.txt` outputs ` "$0}' tlds-alpha-by-domain.txt2 AC`etc... Using the longer version without tabs generates safer terminal/command output. At least when running in bash version 3.2 on Mac OS X 10.7.5. – Pro Backup Jan 22 '13 at 12:56
  • 2
    @thiton: You can put the filename at the front without using `cat`, like this: `< input_file command1 | command2 | commmand3 > output_file` – Keith Thompson Jul 17 '13 at 04:24
  • I'm using the similar way to find the first `build.gradle` by using: `find $PWD -name "build.gradle" | awk '{print length($0), $0 | "sort -n"}' | head -1 | cut -d ' ' -f 2-` – Marslo Jul 06 '17 at 05:57
4

TIM (my terse version for TIMTOWTDI... hmm but now it's long already :(

perl -ne '@a = <>; print sort { length $b <=> length $a } @a' file

lets reserve reverse and push when needed

and I wonder how long it would take on that 550MB file

lzc
  • 919
  • 7
  • 16
2

Perl version, with a tip of the hat to @thiton:

perl -ne 'print length($_)." $_"' file | sort -r -n | cut -d ' ' -f 2-

$_ is the current line, similar to awk's $0

perl-5.24 execution on a 550MB .txt file with 6 million lines (British National Corpus) took 24 seconds


@thiton's awk (3.1.7) execution took 26 seconds


With a tip of the hat to @William Pursell from a related post:

perl -ne 'push @a, $_; END{ print reverse sort { length $a <=> length $b } @a }' file

perl-5.24 execution took 12.0 seconds

Chris Koknat
  • 3,305
  • 2
  • 29
  • 30
1

With POSIX Awk:

{
  c = length
  m[c] = m[c] ? m[c] RS $0 : $0
} END {
  for (c in m) q[++x] = m[c]
  while (x) print q[x--]
}

Example

Zombo
  • 1
  • 62
  • 391
  • 407