5

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
    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. – Wildcard Dec 16 '15 at 7:46
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.

|improve this answer|||||
  • 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. – fifaltra Dec 16 '15 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. – 123 Dec 16 '15 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')" – mikeserv Dec 16 '15 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. – mikeserv Dec 16 '15 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 – 123 Dec 16 '15 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
|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.