Perl script solution

Hi
I need to do this thing in awk (or perl?). I try to find out how can I identify 1st and 2nd result from the OR expression in gensub:

block='title Sata Mandriva
kernel /boot/vmlinuz
initrd /boot/initrd.img'
echo "$block" | awk '{ x=gensub(/(kernel|initrd) /,"\\1XXX","g"); print x }'

Generates this:

title Sata Mandriva
kernelXXX/boot/vmlinuz
initrdXXX/boot/initrd.img

Now I need to apply the change only on 1st found result:

title Sata Mandriva
kernelXXX/boot/vmlinuz
initrd /boot/initrd.img

Problem is that I don't know how to identify the 1st and second substitution.

Somebody help?

Hi webhope!

What do you want exactly? To replace only the first occurrence of either `initrd' or `kernel' in the whole stdin text? Or simply replace `kernel' with `kernelXXX' in this particular variable? And what does NFR mean - may be it should be FNR (record number)?

Why must it be awk?

---------- Post updated at 02:37 PM ---------- Previous update was at 02:25 PM ----------

$> cat infile
title Sata Mandriva
kernel /boot/vmlinuz
initrd /boot/initrd.img
$> echo "$block"| awk '/(kernel|initrd)/ && f!=1 {sub(/ /,"XXX"); f=1; print; next}1' f=0
title Sata Mandriva
kernelXXX/boot/vmlinuz
initrd /boot/initrd.img

that was mistake:
not print x NFR
but
print x

I gave you simplified form of code.

I must to explain you what I want to do.

Originally. I had something like ... kernel (hd0,2) ... root=(hd0,2) .... I replaced it with ...

kernel (UUID=theuuid) ... root=(UUID=theuuid)
initrd (UUID=theuuid) 

It is not ideal but what I do in previous code is that I replace (hd?,?) for uuid and uuid for (hd?,?)

My code was:

block=$( echo "$block" | awk '{ x=gensub(/(kernel|init)( +)\(UUID=[-0-9a-f]*\)/,"uuid '$two'\\\\n\\1 ","g"); print x}' );

Original input text was like:

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

Includes \n twice fot newline character.
See:

\nkernel (UUID=
\ninitrd /boot/initrd.img

I tried your code, but it result in:

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

---------- Post updated at 03:58 PM ---------- Previous update was at 03:30 PM ----------

:cool:

What I want to do:
The 1st found result from (..|..) to give on separete line with uuid:
change this:

kernel (UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c) /boot ...
initrd (UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c) /boot

to this:

uuid UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c
kernel /boot...
initrd /boot...

It is important to specify we look for kernel or initrd. "initrd (UUID=... " or "kernel (UUID=..." .
Because there also can occur words like "unhide (UUID=" or "hide (UUID=" or similar.

I am not sure if I understood it completely, anyway:

$> echo "$block"
kernel (UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c) /boot ...
initrd (UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c) /boot
$> echo "$block"| awk '/^(kernel|initrd) / && f!=1 {f=1; p=$1; r=$3$4; gsub(/[()]/,"",$2); print "uuid",$2; print p,r; next} /^(kernel|initrd) / && f==1 {print $1,$3; next}' f=0
uuid UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c
kernel /boot...
initrd /boot

Not sure if there are more similar blocks in this config etc. which relations to which parameters you have etc.

---------- Post updated at 04:43 PM ---------- Previous update was at 04:26 PM ----------

Changed sub to gsub - there was ) left being not substituted by " " - just in case so you notice.

Yes, it is menu.lst
It is almost working but...

block='title Sata Mandriva
kernel (UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c) /boot ...
initrd (UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c) /boot'

echo "$block"| awk '/^(kernel|initrd) / && f!=1 {f=1; p=$1; r=$3$4; sub(/[()]/,"",$2); print "uuid",$2; print p,r; next} /^(kernel|initrd) / && f==1 {print $1,r; next}' f=0

Produces:

uuid UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c)
kernel /boot...
initrd /boot...

It should not remove the title ... and other lines ...
In fact $block doesn't need to have the kernel or init attributes. It can be block for Linux or Windows with map command. So if no kernel or initrd in it, then save it untouched.

I changed the sub vs gsub for the ) that got not substituted - stated it in an update but you answered already :wink:

Try this one:

echo "$block"| awk '/^(kernel|initrd) / && f!=1 {f=1; p=$1; r=$3$4; gsub(/[()]/,"",$2); print "uuid",$2; print p,r; next} /^(kernel|initrd) / && f==1 {print $1,$3; next}1' f=0

) is substituted and the title should not be touched.

It is stil not ideal, I send you some other forms if input text:

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

hd0,2 instead (hd0,2)

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

It deletes some spaces: products "linuxroot" instead "linux root"

block='title Sata Mandriva
kernel (UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c) /boot (UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c) blabla
initrd (UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c) /boot (UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c) blabla'

Products "/boot(UUID=" instead "/boot (UUID="
and "/boot" instead "/boot (UUID=eab515e9-"
Edit: I wanted to specify that I need to remove something (UUID=...) that follows the kernel or initrd word.

In my original code I tried to identify UUID format \(UUID=[-0-9a-f]*\ not to be confused with block list (hd?,?). (I am not sure if UUID can have big letters)

I think it is not lucky: sub(/[()]/,"",$2) it removes the parantheses whatever it it uuid od hd. Or Map! map (hd0) (hd1)

I want to ask you about this: r=$3$4; does it mean, you rely on IFS=$' '? How we get $3 and $4 ?

I used the default FS of awk which is [:space:]+ or [ \t]+. I did not touch shell's IFS.

You posted an excerpt and I responded to it - if there is more cases of what can be in your menu.lst, then you have to post them :wink:

It is difficult when there is a lot of different things coming new with every new example of your input.

Best might be to just post all different examples and possibilities and according to that your expected output. Else it will never be completed :wink:

Sorry. It is always hard to me to explain what I work with and where I am going to. I always try to simplify things therefor I 1st publish the simplest form... To better understand. But I see this doesn't work and it is just on the contrary... :frowning:

No worries - as said, best try to gather what you want to do with a complete example of the input (describing cases etc. with comments) and a complete example of the wanted output.
There is a lot of more people here in the forum which will be able to help for sure - having a break from work for today, see you tomorrow :wink:

I'd like to do a remake.

It is good you showed me how to identify the 1st found result of (kernel|init).
Now I would need to access the content of parenthesis (.*) by some referencer.

I will do a remake. In this example I use //1 as a referencer (it is kust to show where I want to access the captured word).

I have this code:

/^(kernel|initrd)( +)(\(UUID=[-0-9a-f]*\)?)(.*)/ && f!=1 {f=1;
                    print "uuid"; print \\1;
                    next }
/^(kernel|initrd) / && f==1 {
                    next }1' f=0

Is some referencer to access the parenthesis? The FS - spaces and $1,$2,$3 referencer is a problem for me. I would better not use it. I don't know if the \\1 referencer is only for gensub? If I could use this I would use print \\1\\2\\3\\4 to print the content of parenthesis.

---------- Post updated at 08:54 PM ---------- Previous update was at 08:07 PM ----------

I have found interesting thread about storing data and backreferences . So I don't know if is it possible to do it in awk. Maybe if somebody would do it in perl.

storing data and backreferences

Hi, here I am again. I have learned some basic about perl and I am bringing a solution. If zou know better way how to do it in perl, show it to me. I am newbie to perl :slight_smile:

The text I work with 3 lines:

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

Now it is on one line, but later I get it to array with 3 rows.

---------- Post updated at 10:23 PM ---------- Previous update was at 06:00 PM ----------

Step A) This code removes 1st UUID=... from the line with kernel (or initrd) and move it to newline as uuid UUID=...
1) I needed to recognize if the initrd or kernel was found - therefor the step A was done now.
2) If step A is done, then I do second part. I print the initrd without UUID and without "uuid"
B) I do increment $n++ for setting the array in which I have the lines.
C) ($1 eq "") is necessary to recognize if kernel or initrd was find. If not, then I need to put original line as value to the array.

block=$(
echo "$block" | perl -e '
$/="\\n";
chomp (@ia=<STDIN>);
foreach $i (@ia) {
  $n++; @p[$n]=$i;

  if ($q!=1)  
    {
    $i =~ /^(kernel|initrd)( +)(\(UUID=[-0-9a-f]*\)?)(.*)/ ;
    if ($1 eq "") { @p[$n]=$i; } else {   # if it is not kernel nor initrd I have to set the original value for this line
    $u=$3;
    $q=1;
    $a="$1 $2$4\n";
    $u =~ s/[()]//g;
    @p[$n]="\\nuuid $u\\n$a\\n";
    } 
    } elsif ($q==1) { $q=2; }

  if ($q==2)  
    { 
    $i =~ /^(kernel|initrd)( +)(\(UUID=[-0-9a-f]*\)?)(.*)/ ; 
    if ($1 eq "") { @p[$n]=$i; } else {   # if it is not kernel nor initrd I have to set the original value for this line
    $b="$1 $2$4\n"; 
    @p[$n]="$b\\n";
    }
    }; 
}
print @p; $q=0;
' 
);