7

Recently, I asked a question how to sort pairs of lines, and one of the answers suggested concatenating lines with sed, like this:

cat file.txt | sed -n 'N;s/\n//;p' | sort -t";" -k43,43n | perl -F';' -ane '$,=";";print @F[0..13],"\n";print @F[14..$#F]'

which worked brilliantly, but now my problem generalized to sorting n-tupels of lines, which I can't figure out how to do with sed.

Everything I found was either for 2 lines or ALL lines, but I need n lines (where n is 5 at the moment, but a general way would be great).

Bonus points for a nice way of rewriting the perl part to accomodate n lines, but the problem is really about the sed part.

I am also not hung on sed specifically, so if you have a nice solution using a different command line tool, please post it.

Update: Example input (n == 3)

a1;b1;c1; 
n1;m1;l1; 
d1;e1;f1;g1
n2;m2;l2;
a2;b2;c2;
d2;e2;f2;g2
1
  • 1
    On this type of question it's usual to include a sample input and sample output to illustrate what you want. It sounds like perl's paragraph mode might be of use here but I'm not sure I get what you're after. Commented Dec 16, 2015 at 7:46

2 Answers 2

5
sed -e:n -e$\bo -e'N;s/\n/&/4;to' -ebn -e:o -e'y/\n/ /' <in >out

That will concatenate 5 lines - or 1 + 4 lines - replacing each newline with a single space. However:

paste -d\  - - - - - <in >out

...would also work.

Your g sort thing could work like:

paste -d\  - - <input   |
sed 's/.*;\(.*\)/\1;&/' |
sort -t\; -k1,1         |
cut  -d\; -f2-          |
tr \  \\n

...which would be a fairly general way of doing it, though it relies on there being no spaces in the input file. it joins every two lines on a space, the copies the last ; split field to the head of each line, sorts on the first field, then cuts it away and splits the lines back out.

12
  • 1
    Wow, the combination of paste and tr is perfect for this problem! So concise! I can't use the sed and cut trick however, because it is not actually the last field I want to sort on. Commented Dec 16, 2015 at 8:06
  • 2
    In the event that you want more lines concatenated and not hundreds of - you can use xargs -n5 <file instead of paste, where 5 is the number of lines to be concatenated. Commented Dec 16, 2015 at 9:21
  • 2
    @User112638726 - that's an entirely different thing. that's an exec of /bin/echo for every five input lines. if you don't want to type out hundreds of - dashes something like: set "" - -; while [ "$#" -lt 100 ]; set "$@$@"; done; shift "$(($#-100))"; paste "$@" or eval paste "$(printf %100s|sed 's/./- /g')" Commented Dec 16, 2015 at 9:26
  • 1
    @User112638726 - that's a good point, but they don't do so in the loop. in general - in my experience - it is far better to do a little more work to prepare a loop than it is to otherwise do the work during the loop. the loop, in this case, is the processing of the input file. in my suggestions the extra stuff only happens the one time to build an argument list for paste to afterward take it from there, but with xargs you cut up the argument list and distribute it to all of the different echo invocations. i dunno about your comment -thought it was weird too. i saw it for a second. Commented Dec 16, 2015 at 9:36
  • 2
    fair enough :) IMO it is more apparent what the xargs is doing though and is neater, so if resources are abundant then i personally think it is the better choice. Also the original i posted was wrong and split on all [[:space:]] characters. The command should have been xargs -d'\n' -n5 < file Commented Dec 16, 2015 at 9:42
1

With minor modification, you can use the solution I posted to your other question.

Again using GNU sed and GNU awk and assuming homogeneous structure of the data, use the last element as the sorting key:

# Separate input into records, here 3 lines each
sed '3~3G' infile |

# Use GNU awk's built-in sort, here index-string-descending
awk '
  BEGIN { PROCINFO["sorted_in"] = "@ind_str_desc" }
  { h[$NF] = $0 }
  END { for(k in h) print h[k] }
' RS= FS='[;\n]+'   

Output:

n2;m2;l2;
a2;b2;c2;
d2;e2;f2;g2
a1;b1;c1; 
n1;m1;l1; 
d1;e1;f1;g1
0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.