5

Say I have this list:

sharpest
  tool
  in
the
  shed
im
  not
  the

How can I order alphabetically by the non-indented lines and preserve groups of lines? The above should become:

im
  not
  the
sharpest
  tool
  in
the
  shed

Similar questions exist here and here but I can't seem to make them work for my example.

Hopeful ideas so far

  • Maybe I could use grep -n somehow, as it gives me the line numbers? I was thinking to first get the line numbers, then order. I guess I'd somehow need to calculate a line range before ordering, and then from there fetch the range of lines somehow. Can't even think how to do this however!
  • ranges look promising too, but same deal; sed 1,2p and further examples here.
Nick Bull
  • 9,518
  • 6
  • 36
  • 58

4 Answers4

3

If perl is okay:

$ perl -0777 -ne 'print sort split /\n\K(?=\S)/' ip.txt
im
  not
  the
sharpest
  tool
  in
the
  shed
  • -0777 slurp entire file, so solution not suitable if input is too big
  • split /\n\K(?=\S)/ gives array using newline character followed by non-whitespace character as split indication
  • sort to sort the array
Sundeep
  • 23,246
  • 2
  • 28
  • 103
3

You can use this asort function in a single gnu awk command:

awk '{if (/^[^[:blank:]]/) {k=$1; keys[++i]=k} else arr[k] = arr[k] $0 RS} 
END{n=asort(keys); for (i=1; i<=n; i++) printf "%s\n%s", keys[i], arr[keys[i]]}' file

im
  not
  the
sharpest
  tool
  in
the
  shed

Code Demo


Alternative solution using awk + sort:

awk 'FNR==NR{if (/^[^[:blank:]]/) k=$1; else arr[k] = arr[k] $0 RS; next}
{printf "%s\n%s", $1, arr[$1]}' file <(grep '^[^[:blank:]]' file | sort)

im
  not
  the
sharpest
  tool
  in
the
  shed

Edit: POSIX compliancy:

#!/bin/sh
awk 'FNR==NR{if (/^[^[:blank:]]/) k=$1; else arr[k] = arr[k] $0 RS; next} {printf "%s\n%s", $1, arr[$1]}' file | 
  grep '^[![:blank:]]' file | 
  sort
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • Thank you for the POSIX! Only gave it to Sundeep as he was first – Nick Bull Feb 22 '18 at 11:03
  • @NickBull imo you should choose answer which better suits you :) not based on who happened to see and answer the question first.. – Sundeep Feb 22 '18 at 11:05
  • @Sundeep I didn't specify that when I should have, and (I hope) you can't read my mind! :) So yours is the first correct answer. Thank you both – Nick Bull Feb 22 '18 at 11:07
  • @anubhava Actually just double-checking the first script and it doesn't seem to work! It only prints the nonintended phrases in order. – Nick Bull Feb 22 '18 at 11:22
  • I have added a [working code demo](https://ideone.com/DQKHIO) in my answer for first awk command. As I mentioned it requires a `gnu awk` – anubhava Feb 22 '18 at 11:32
  • 1
    @anubhava In fact scrap that comment. This works fine, I must've been doing something dumb. – Nick Bull Feb 22 '18 at 11:33
1

With single GNU awk command:

awk 'BEGIN{ PROCINFO["sorted_in"] = "@ind_str_asc" }
     /^[^[:space:]]+/{ k = $1; a[k]; next }
     { a[k] = (a[k]? a[k] ORS : "")$0 }
     END{ for(i in a) print i ORS a[i] }' file

The output:

im
  not
  the
sharpest
  tool
  in
the
  shed
RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
0

awk one-liner

$ awk '/^\w/{k=$1; a[k]=k; next} {a[k]=a[k] RS $0} END{ n=asorti(a,b); for(i=1; i<=n; i++) print a[b[i]] }' file
im
  not
  the
sharpest
  tool
  in
the
  shed
Rahul Verma
  • 2,946
  • 14
  • 27