LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 04-23-2010, 04:23 AM   #1
webhope
Member
 
Registered: Apr 2010
Posts: 184

Rep: Reputation: 30
awk - How to get a block of lines


Hi,
I tried to get a block of lines in awk, but unfortunately it returns output of one line only. I don't state the code here, because it's too short and too poor. What exactly I wanted to do: from file "/boot/grub/menu.lst" get blocks of lines, starting by title and ending by \n\n

Now I have just

Code:
script="/boot/grub/menu.lst";
OLDIFS=$IFS; IFS=$'\n';
content=($(cat $script |
    awk '' ));
echo ${content[2]}
read
I want to get every block as one row of array. Can you help me with this? Thanks
 
Old 04-23-2010, 05:17 AM   #2
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983
Quote:
Originally Posted by webhope View Post
I want to get every block as one row of array
Hi. What do you mean for 'as one row'? Arrays in bash are not multi-dimensional (you can only mimic them using indirect variable reference). Maybe do you want to assign one block of lines to a single element of the array?
 
Old 04-23-2010, 05:35 AM   #3
webhope
Member
 
Registered: Apr 2010
Posts: 184

Original Poster
Rep: Reputation: 30
Quote:
Originally Posted by colucix View Post
Maybe do you want to assign one block of lines to a single element of the array?
I think so. If the "single element" means array[0], array[1], etc. Other words I mean output like this:

Code:
array[0]='title           Ubuntu 9.04 - boot_ide 160GB uuid
uuid            40af8b13-eb6d-4257-bace-50ba2e5ce544
kernel          /boot/vmlinuz-2.6.28-11-generic root=UUID=40af8b13-eb6d-4257-bace-50ba2e5ce544b ro xforcevesa quiet splash
initrd          /boot/initrd.img-2.6.28-11-generic
quiet
' 
array[1]='Next block
asd
asd
'
 
Old 04-23-2010, 06:11 AM   #4
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian
Posts: 8,578
Blog Entries: 31

Rep: Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208
This should do it
Code:
#!/bin/bash

readonly false=
readonly true=true

in_stanza_flag=$false
i=-1
while read line
do
    case $line in
        title* )
            let i++
            in_stanza_flag=$true
            ;;
        * )
    esac
    [[ $in_stanza_flag ]] && array[i]=${array[i]}$line$'\n'
done < /boot/grub/menu.lst

for (( i=0; i<${#array[*]}; i++ ))
do
    echo "Stanza $i"$'\n'"${array[i]}"
done
If there is stuff after the end of the stanzas list you can replace the case statement's wild (*) case with a string match for it and code in_stanza_flag=$false to avoid all the remaining guff ending up in the last array element.
 
Old 04-23-2010, 06:18 AM   #5
webhope
Member
 
Registered: Apr 2010
Posts: 184

Original Poster
Rep: Reputation: 30
Question

catkin:
Uff. This looks complicated. I hoped in some simple solution on one or two lines by awk. I think awk is much more better because it uses strong regular expressions. But thanks for your efforts.

Last edited by webhope; 04-23-2010 at 06:22 AM.
 
Old 04-23-2010, 07:14 AM   #6
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
Code:
awk 'BEGIN{RS=""}/^title/' /boot/grub/menu.lst
 
1 members found this post helpful.
Old 04-23-2010, 08:01 AM   #7
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian
Posts: 8,578
Blog Entries: 31

Rep: Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208
Quote:
Originally Posted by grail View Post
Code:
awk 'BEGIN{RS=""}/^title/' /boot/grub/menu.lst
That's cunning. How does it work?
 
Old 04-23-2010, 08:06 AM   #8
webhope
Member
 
Registered: Apr 2010
Posts: 184

Original Poster
Rep: Reputation: 30
Quote:
Originally Posted by grail View Post
Code:
awk 'BEGIN{RS=""}/^title/' /boot/grub/menu.lst
What's wrong? I have problem with it even with my variation.

menu.lst
Code:
timeout 5                                                                
color black/cyan yellow/cyan                                             
gfxmenu (hd0,2)/boot/gfxmenu                                             
default 0                                                                

title Sata Mandriva
kernel (hd0,2)/boot/vmlinuz BOOT_IMAGE=linux root=UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c  resume=UUID=e12487ff-6d6f-44c4-9e03-33f545b3b798 splash=silent vga=788                                                           
initrd (hd0,2)/boot/initrd.img                                                                                 


title sata XP
 unhide (hd0,0)                 
 hide (hd0,1)                   
rootnoverify (hd0,0)            
chainloader +1                  
makeactive                      
savedefault
Output:
Code:
# clear; script="/boot/grub/menu.lst";
# content=($( awk 'BEGIN{RS="\n"}/^title/' $script ));
# echo ${content[0]}
title
# echo ${content[1]}
Sata
# echo ${content[2]}
Mandriva
# echo ${content[3]}
title
# echo ${content[4]}
sata
[root@localhost grub]# echo ${content[5]}
XP1
(Missing IFS=$'\n')


My code:
Code:
clear; script="/boot/grub/menu.lst";
content=($( awk 'BEGIN{RS=""}/^title/' $script ));
echo ${content[1]}
Code 2
Code:
IFS=$'\n';
clear; script="/boot/grub/menu.lst";
content=($( awk 'BEGIN{RS="\n"}/^title/' $script ));
echo ${content[0]}
Outputs:
Code:
# echo ${content[0]}
title Sata Mandriva
# echo ${content[1]}
title sata XP
In 1st case it is words of 1st line of block 1, then words of 1st line of next block.

In 2nd case it is 1st line of next block.

I need to edit 2nd code (having IFS=$'\n' to get next lines of the same block to content[n]. So output should be:

Code:
# echo ${content[0]}
title Sata Mandriva
kernel (hd0,2)/boot/vmlinuz BOOT_IMAGE=linux root=UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c  resume=UUID=e12487ff-6d6f-44c4-9e03-33f545b3b798 splash=silent vga=788                                                           
initrd (hd0,2)/boot/initrd.img

Last edited by webhope; 04-23-2010 at 08:09 AM.
 
Old 04-23-2010, 08:33 AM   #9
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
Quote:
That's cunning. How does it work?
Setting the record separator to blank allows you to look through the file and keep all consecutive lines that contain
something together, so now in your normal grub file a $0 may look like:
Code:
title		Ubuntu 9.10, kernel 2.6.31-21-generic
root		(hd0,1)
kernel		/boot/vmlinuz-2.6.31-21-generic root=/dev/mapper/isw_cehbidjbfj_RaidME2 ro quiet splash 
initrd		/boot/initrd.img-2.6.31-21-generic
@OP - The solution I presented was able to get the necessary lines, but I would hazard a guess that no amount of playing with IFS will work
as it does not take a regular expression as an option (that I know of).
Basically you can't have your cake and eat it too, either you use something like catkin had or if using something like the awk you will need to change
how you deal with the data, ie into an array may not be the best option.
You could perhaps also try converting the awk to output each field using a different separator, maybe pipe, and then use your IFS='\n',
but of course then you need a way to break it back up at the other end.

Maybe if you would enlighten us a little further as to what you need to do with each stanza from menu.lst?
 
Old 04-23-2010, 08:52 AM   #10
webhope
Member
 
Registered: Apr 2010
Posts: 184

Original Poster
Rep: Reputation: 30
I am going to write a script where I can do this actions:
1) change title
2) change hdx to uuid or uuid to hdx
3) increase hdx+1 or descrease hdx-1
4) save

Similar to script I did yesterday.

Last edited by webhope; 04-23-2010 at 08:54 AM.
 
Old 04-23-2010, 09:10 AM   #11
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian
Posts: 8,578
Blog Entries: 31

Rep: Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208
Quote:
Originally Posted by grail View Post
Setting the record separator to blank allows you to look through the file and keep all consecutive lines that contain
something together, so now in your normal grub file a $0 may look like:
Code:
title		Ubuntu 9.10, kernel 2.6.31-21-generic
root		(hd0,1)
kernel		/boot/vmlinuz-2.6.31-21-generic root=/dev/mapper/isw_cehbidjbfj_RaidME2 ro quiet splash 
initrd		/boot/initrd.img-2.6.31-21-generic
Thanks, grail. Neat!
 
Old 04-23-2010, 09:25 AM   #12
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983
@webhope: if you want each element of the array contain multiple lines, you cannot use "\n" as IFS. Following grail's suggestion you can choose a character that does not appear in menu.lst stanzas, e.g. @, then simply:
Code:
#!/bin/bash
OLD_IFS=$IFS
IFS="@"
content=( $(awk 'BEGIN{RS=""; ORS="@"}/^title/' /boot/grub/menu.lst) )
IFS=$OLD_IFS
echo ${content[0]}

Last edited by colucix; 04-23-2010 at 10:16 AM. Reason: Language mistakes... ;)
 
Old 04-23-2010, 09:25 AM   #13
webhope
Member
 
Registered: Apr 2010
Posts: 184

Original Poster
Rep: Reputation: 30
I don't understand how you get the block of lines. When I run your code

Code:
awk 'BEGIN{RS=""}/^title/' /boot/grub/menu.lst
I have something like this:
Code:
title           Ubuntu 9.04, kernel 2.6.28-11-generic                                                          
uuid            40af8b13-eb6d-4257-bace-50ba2e5ce544                                                           
kernel          /boot/vmlinuz-2.6.28-11-generic root=UUID=40af8b13-eb6d-4257-bace-50ba2e5ce544 ro xforcevesa quiet splash                                                                                                     
initrd          /boot/initrd.img-2.6.28-11-generic                                                             
quiet                                                                                                          
title           Ubuntu 9.04 - boot_sata 500GB                                                                  
root (hd0,2)                                                                                                   
kernel          /boot/boot_sata/vmlinuz-2.6.28-11-generic root=/dev/sda3 ro xforcevesa access=v2 quiet splash  
# uuid          40af8b13-eb6d-4257-bace-50ba2e5ce544                                                           
# kernel                /boot/boot_sata/vmlinuz-2.6.28-11-generic root=UUID=40af8b13-eb6d-4257-bace-50ba2e5ce544 ro xforcevesa access=v2 quiet splash                                                                         
initrd          /boot/boot_sata/initrd.img-2.6.28-11-generic
quiet
title           Ubuntu 9.04 - boot_ide 160GB - root hd1,4
root (hd0,4)
kernel          /boot/vmlinuz-2.6.28-11-generic root=/dev/sdb1 ro xforcevesa quiet splash
initrd          /boot/initrd.img-2.6.28-11-generic
quiet
 
Old 04-23-2010, 10:08 AM   #14
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
Quote:
title Ubuntu 9.04, kernel 2.6.28-11-generic
uuid 40af8b13-eb6d-4257-bace-50ba2e5ce544
kernel /boot/vmlinuz-2.6.28-11-generic root=UUID=40af8b13-eb6d-4257-bace-50ba2e5ce544 ro xforcevesa quiet splash
initrd /boot/initrd.img-2.6.28-11-generic
quiet
So this is one of the stanzas from your menu.lst.

If you know follow colucix advice, you can even use select:
Code:
#!/bin/bash
OLD_IFS=$IFS
IFS="@"
content=( $(awk 'BEGIN{RS=""; ORS="@"}/^title/' /etc/grub/menu.lst) )

select x in ${content[@]}
do
    echo "$x"
done
IFS=$OLD_IFS
 
Old 04-23-2010, 10:24 AM   #15
webhope
Member
 
Registered: Apr 2010
Posts: 184

Original Poster
Rep: Reputation: 30
Sorry I didn't see colucix response. I will try
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] awk print only lines {not}containing FS grail Programming 8 04-12-2010 04:41 AM
search for blank lines with awk _vibeke_ Linux - Newbie 5 11-04-2009 01:54 AM
Delete lines using awk kkjegan Programming 13 09-11-2007 07:36 PM
awk/gawk/sed - read lines from file1, comment out or delete matching lines in file2 rascal84 Linux - General 1 05-24-2006 09:19 AM
awk text that is on several lines homey Programming 2 10-31-2004 09:27 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 07:36 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration