BASH: Sort four lines based on first line


 
Thread Tools Search this Thread
Top Forums Shell Programming and Scripting BASH: Sort four lines based on first line
# 1  
Old 09-18-2011
BASH: Sort four lines based on first line

I am in the process of sorting an AutoHotkey script's contents so as to make it easier for me to find and view its nearly 200 buzzwords (when I forget which one corresponds with what phrase, which I do now and then).

About half to two-thirds of the script's key phrases correspond to locations (see example data). These are the ones I've been trying to sort first.

My data looks like this:
Code:
;Canyon
::grand::
Send, Canyon
Exit

;Elevator
::lift::
Send, Elevator
Exit

;Office
::9to5::
Send, Office
Exit

;Cabin
::log::
Send, Cabin
Exit

;Desert
::sahara::
Send, Desert
Exit

;Front door
::welcome::
Send, Front door

In order for this data to work in the AHK script once it's sorted, it has to remain multi-line. I admit I'm somewhat bummed because the sort command works line-by-line and is not appropriate for what I want to do.

So what would be a good method for sorting just these groups of 4 lines (for example), by the first line in each one, as they stand?

BZT
# 2  
Old 09-18-2011
If you are maintaining the file, and thus have control over it's format, I'd suggest keeping your "source" as one record per 4 line entry like this:

Code:
;Canyon|::grand::|Send,|Canyon|Exit|
;Elevator|::lift::|Send,|Elevator|Exit|
;Office|::9to5::|Send,|Office|Exit|
;Cabin|::log::|Send,|Cabin|Exit|
;Desert|::sahara::|Send,|Desert|Exit|
;Front door|::welcome::|Send,|Front door|Exit|

Then you could use a simple sort and awk to generate the real file:
Code:
sort source_file|awk -v RS="|" '1' >ahk.file

This assumes that there are no vertical bars in any of the four lines. There weren't any in your example, but that might not hold across all of your data.

Output from the above data:
Code:
;Cabin
::log::
Send,
Cabin
Exit

;Canyon
::grand::
Send,
Canyon
Exit

;Desert
::sahara::
Send,
Desert
Exit

;Elevator
::lift::
Send,
Elevator
Exit

;Front door
::welcome::
Send,
Front door
Exit

;Office
::9to5::
Send,
Office
Exit

---------- Post updated 09-18-11 at 00:04 ---------- Previous update was 09-17-11 at 23:54 ----------

And if you don't have control over the script file, you could do something like this:

Code:
awk 'NF < 1 {next;} { x=x $0 "|"; } /Exit/ { print x; x="" }' script_file | sort | awk -v RS="|" '1' >new_ahk.file

which will join the lines into one, sort and then split them back out again.
This User Gave Thanks to agama For This Post:
# 3  
Old 09-18-2011
Quote:
Originally Posted by agama
Code:
awk 'NF < 1 {next;} { x=x $0 "|"; } /Exit/ { print x; x="" }'

The following alternative is a bit simpler (though more cryptic for AWK newbies), a bit more tolerant of changing data format, and should also be portable across AWK implementations:
Code:
awk '{$NF=$NF OFS}1' FS=\\n RS= OFS=\|

Regards,
Alister

Last edited by alister; 09-18-2011 at 01:14 PM.. Reason: Code fix
This User Gave Thanks to alister For This Post:
# 4  
Old 09-18-2011
Code:
perl -0777 -F'/\n\n+/' -ane '                                                
print join "\n\n",
  map  { $_->[1] }
  sort { $a->[0] cmp  $b->[0] }
  map  { [(split /\n/)[0], $_] } @F;                      
print "\n"' INPUTFILE

This User Gave Thanks to yazu For This Post:
# 5  
Old 09-18-2011
Quote:
Originally Posted by agama
If you are maintaining the file, and thus have control over it's format, I'd suggest keeping your "source" as one record per 4 line entry like this:

Code:
;Canyon|::grand::|Send,|Canyon|Exit|
;Elevator|::lift::|Send,|Elevator|Exit|
;Office|::9to5::|Send,|Office|Exit|
;Cabin|::log::|Send,|Cabin|Exit|
;Desert|::sahara::|Send,|Desert|Exit|
;Front door|::welcome::|Send,|Front door|Exit|

Then you could use a simple sort and awk to generate the real file:
Code:
sort source_file|awk -v RS="|" '1' >ahk.file

This assumes that there are no vertical bars in any of the four lines. There weren't any in your example, but that might not hold across all of your data.

Output from the above data:
Code:
;Cabin
::log::
Send,
Cabin
Exit

;Canyon
::grand::
Send,
Canyon
Exit

;Desert
::sahara::
Send,
Desert
Exit

;Elevator
::lift::
Send,
Elevator
Exit

;Front door
::welcome::
Send,
Front door
Exit

;Office
::9to5::
Send,
Office
Exit

This looks good, except I'm pretty sure that in AHK, the "Send," and whatever comes after it must be on the same line to work -- it's a command syntax. So that may present an obstacle when reformatting the source (which I do have control over, btw).

I suppose a tr that turns the newlines into pipe symbols, like you have above, may work, but any tr I may run would also get rid of the spaces in between these "quatrains" (which is OK for ahk but would make a quick perusal of the resulting sorted list rather a pain) and leave me with a block of data it would take a lot more time to reformat.

I thought of customizing the IFS to just "/n" (newline), but I think that here, too, I'd lose those empty lines in between. So if I were to use this approach, maybe also including the ";" in the temporary IFS might do it?

It occurs to me I could also preserve those newlines by introducing an echo command somewhere, but where to put it?

Thanks for your help so far.

BZT

---------- Post updated at 11:38 ---------- Previous update was at 09:42 ----------

agama -- How did you get the sample data I posted to look like it does in the first CODE block of your reply. I've been trying for over an hour* to do the same with some of my own data , and it's still escaping me. I presume you used awk...?
BZT

*and about 20 minutes making this "quick" [ahem] reply...

Last edited by SilversleevesX; 09-18-2011 at 12:38 PM.. Reason: Wasn't positive about s/t in AHK
# 6  
Old 09-18-2011
Code:
$
$ cat datafile
;Canyon
::grand::
Send, Canyon
Exit

;Elevator
::lift::
Send, Elevator
Exit

;Office
::9to5::
Send, Office
Exit

;Cabin
::log::
Send, Cabin
Exit

;Desert
::sahara::
Send, Desert
Exit

;Front door
::welcome::
Send, Front door
$
$
$ perl -ne '$k = $_ if /^;.*/; $x{$k} .= $_;
            END { $x{$k} .= "$_\n";
                  foreach $key (sort keys %x) {print $x{$key}}
            }' datafile
;Cabin
::log::
Send, Cabin
Exit

;Canyon
::grand::
Send, Canyon
Exit

;Desert
::sahara::
Send, Desert
Exit

;Elevator
::lift::
Send, Elevator
Exit

;Front door
::welcome::
Send, Front door

;Office
::9to5::
Send, Office
Exit

$
$

tyler_durden
This User Gave Thanks to durden_tyler For This Post:
# 7  
Old 09-18-2011
I completely missed that the send, was being placed on its own line in the output!! Initially I was using spaces to separate the fields and realised that there were embedded spaces and when I converted to pipes I added an unnecessary vertical bar. The 'source' file should be something like:

Code:
;Canyon|::grand::|Send, Canyon|Exit|
;Elevator|::lift::|Send, Elevator|Exit|
;Office|::9to5::|Send, Office|Exit|
;Cabin|::log::|Send, Cabin|Exit|
;Desert|::sahara::|Send, Desert|Exit|
;Front door|::welcome::|Send, Front door|Exit|

Where the vertical bar after Send, is removed.

I generated the first set of output using the above input and this command:

Code:
sort input-source | awk -v RS="|" '1'

To run with your current file, this should work:

Code:
awk 'NF < 1 {next;} { x=x $0 "|"; } /Exit/ { print x; x="" }' input-file | sort  | awk -v RS="|" '1'

I just recut/pasted your sample data (to be sure I hadn't buggered something up along the way) and ran it through the above pipeline; it generated:

Code:
;Cabin
::log::
Send, Cabin
Exit

;Canyon
::grand::
Send, Canyon
Exit

;Desert
::sahara::
Send, Desert
Exit

;Elevator
::lift::
Send, Elevator
Exit

;Front door
::welcome::
Send, Front door
Exit

;Office
::9to5::
Send, Office
Exit

I did add a final Exit -- I hope that there is one, otherwise things might not work quite right.

Hope this helps.
This User Gave Thanks to agama For This Post:
Login or Register to Ask a Question

Previous Thread | Next Thread

10 More Discussions You Might Find Interesting

1. UNIX for Beginners Questions & Answers

Reading a file line by line and print required lines based on pattern

Hi All, i want to write a shell script read below file line by line and want to exclude the lines which contains empty value for MOUNTPOINT field. i am using centos 7 Operating system. want to read below file. # cat /tmp/d5 NAME="/dev/sda" TYPE="disk" SIZE="60G" OWNER="root"... (4 Replies)
Discussion started by: balu1234
4 Replies

2. Shell Programming and Scripting

How do i sort lines lexigraphical in bash?

I am currently having some problems with my script not sorting my files lexiographically. The error seem to be localized here where i sort the utt2spk file, which is done like this.. for x in test train; do for f in text utt2spk; do sort data/$x/$f -o... (7 Replies)
Discussion started by: kidi
7 Replies

3. Shell Programming and Scripting

Sort file based on number of delimeters in line

Hi, Need to sort file based on the number of delimeters in the lines. cat testfile /home/oracle/testdb /home /home/oracle/testdb/newdb /home/oracle Here delimeter is "/" expected Output: /home/oracle/testdb/newdb /home/oracle/testdb /home/oracle /home (3 Replies)
Discussion started by: Sumanthsv
3 Replies

4. UNIX for Advanced & Expert Users

Sort words based on word count on each line

Hi Folks :) I have a .txt file with thousands of words. I'm trying to sort the lines in order based on number of words per line. Example from: word word word word word word word word word word word word word word word word to desired output: word (2 Replies)
Discussion started by: martinsmith
2 Replies

5. Shell Programming and Scripting

Remove duplicate lines based on field and sort

I have a csv file that I would like to remove duplicate lines based on field 1 and sort. I don't care about any of the other fields but I still wanna keep there data intact. I was thinking I could do something like this but I have no idea how to print the full line with this. Please show any method... (8 Replies)
Discussion started by: cokedude
8 Replies

6. UNIX for Dummies Questions & Answers

Sort data by the end of each line using BASH.

I am trying to sort data within a text document by the information at the end of each line. Please see below for an example: <Profile_0 Name="Random name 0" Description="This is the description." Category="System" ProfileFlags.DWD="6" ABCD="{FF350E61-4FFF-4600-BFFF-3B27DD4BA746}"/>... (6 Replies)
Discussion started by: Davinator
6 Replies

7. UNIX for Dummies Questions & Answers

sort lines in different files based on the starting letter

Hi ,, i have the below file... D 2342135 B 214236 C argjlksd V lskjrghaklsr C slkrgj B sdg4tsd E aslkgjlkasg i want to sort the lines into different files based on the starting letter of the line. so that i have different files for lines starting with a letter. thanks (1 Reply)
Discussion started by: jathin12
1 Replies

8. UNIX for Dummies Questions & Answers

sort group of n lines base on pattern in first line

I have record having 10 fields and each field being printed on a new line, first line cotains name of exchange, 2nd line stock name, third line stock price, etc etc... now i want to retrieve data only for a particular exchanged and that too only 2nd and 3rd row info... NSE RNRL 70 12 1... (1 Reply)
Discussion started by: manishma71
1 Replies

9. Shell Programming and Scripting

sort entire line based on part of the string

hey gurus, my-build1-abc my-build10-abc my-build2-abc my-build22-abc my-build3-abc basically i want to numerically sort the entire lines based on the build number. I dont zero pad the numbers because thats "how it is" ;-) sort -n won't work because it starts from the beginning. ... (10 Replies)
Discussion started by: gurpal2000
10 Replies

10. Shell Programming and Scripting

Remove lines, Sorted with Time based columns using AWK & SORT

Hi having a file as follows MediaErr.log 84 Server1 Policy1 Schedule1 master1 05/08/2008 02:12:16 84 Server1 Policy1 Schedule1 master1 05/08/2008 02:22:47 84 Server1 Policy1 Schedule1 master1 05/08/2008 03:41:26 84 Server1 Policy1 ... (1 Reply)
Discussion started by: karthikn7974
1 Replies
Login or Register to Ask a Question