1748240 Members
3670 Online
108759 Solutions
New Discussion юеВ

Re: Challenging script

 
Unix or Linux?
Frequent Advisor

Challenging script

I need to append some lines to the end of the of a file. The file consists of blocks of lines that correspond to a particular user E.g. BOB . I need a script that will copy this block of lines (currently nine lines), change the name of the user to the name supplied as a parameter to the script and append it to the end of the file before the line that states:

ErrorLog logs/error_log


I should also point out that on each line, the user name is upper case for the first instance then lower case for the second. Find an example below.

Alias /BOB/block/ "/space/home/dir1/dir2/dir3/block/bob/block/"
Alias /BOB/doc/ "/space/home/dir1/dir2/dir3/block/bob/doc/"
Alias /BOB/out1/ "/space/home/dir1/dir2/dir3/block/bob/out1/"
Alias /BOB/out2/ "/space/home/dir1/dir2/dir3/block/bob/out2/"
Alias /BOB/out3/ "/space/home/dir1/dir2/dir3/block/bob/out2/out3/"
Alias /BOB/out4/ "/space/home/dir1/dir2/dir3/block/bob/out2/out4/"
Alias /BOB/test/out3/ "/space/home/dir1/dir2/dir3/block/bob/test/out3/"
Alias /BOB/test/out4/ "/space/home/dir1/dir2/dir3/block/bob/test/out4/"
Alias /BOB/out5/ "/space/home/dir1/dir2/dir3/block/bob/out5/"
ErrorLog logs/error_log
17 REPLIES 17
James R. Ferguson
Acclaimed Contributor

Re: Challenging script

Hi:

This seems to be according to your specifications.

Create a "template" file and name anything you want. I'll call it '/tmp/template'. It should look like:

Alias /UUUUUU/block/ "/space/home/dir1/dir2/dir3/block/uuuuuu/block/"
Alias /UUUUUU/doc/ "/space/home/dir1/dir2/dir3/block/uuuuuu/doc/"
Alias /UUUUUU/out1/ "/space/home/dir1/dir2/dir3/block/uuuuuu/out1/"
Alias /UUUUUU/out2/ "/space/home/dir1/dir2/dir3/block/uuuuuu/out2/"
Alias /UUUUUU/out3/ "/space/home/dir1/dir2/dir3/block/uuuuuu/out2/out3/"
Alias /UUUUUU/out4/ "/space/home/dir1/dir2/dir3/block/uuuuuu/out2/out4/"
Alias /UUUUUU/test/out3/ "/space/home/dir1/dir2/dir3/block/uuuuuu/test/out3/"
Alias /UUUUUU/test/out4/ "/space/home/dir1/dir2/dir3/block/uuuuuu/test/out4/"
Alias /UUUUUU/out5/ "/space/home/dir1/dir2/dir3/block/uuuuuu/out5/"

Now, use the following Perl script:

# cat ./insert
#!/usr/bin/perl
use strict;
use warnings;
die "Usage: $0 name template file\n" unless $#ARGV == 2;
my $name = shift;
my $tempf = shift;
my $template;
{
local $/ = undef;
open( FH, "<", "$tempf" ) or die "Can't open '$tempf': $!\n";
$template = ;
close FH;
}
$template =~ s/UUUUUU/\U$name/g;
$template =~ s/uuuuuu/\L$name/g;
while (<>) {
if (m/^ErrorLog/) {
print $template, $_;
}
else {
print $_;
}
}

...Run your script thusly:

# ./insert jRf /tmp/template /tmp/errorlog > /tmp/errorlog.new

...where the first argument is the user name you want replaced, the second argument is the template file name and the third argument is the name of the file into which you want the modified template inserted.

Regards!

...JRF...
Unix or Linux?
Frequent Advisor

Re: Challenging script

My Perl skills are not too good! Is there any way to do this using SED or AWK ?

Sandman!
Honored Contributor

Re: Challenging script

Based on your post I'm assuming that the lines containing "BOB and bob" are to be replaced by the shell script parameter and after substitution you want those lines copied (within the same file) right before the line that begins with "ErrorLog logs/error_log"

The shell script below does what you're looking for:

============================================
#!/usr/bin/sh -x
ex -s inp <<-EOF
g/BOB/ t /ErrorLog logs\/error_log/-1
%s;/[bB][oO][bB]/;/$1/;g
wq
EOF
============================================

cheers!
James R. Ferguson
Acclaimed Contributor

Re: Challenging script

Hi (again):

> My Perl skills are not too good! Is there any way to do this using SED or AWK ?

Nevertheless, does the script meet your needs? You didn't exclude any tool from the box. You could use 'sed' to perform the regular expression substitutions and pure shell to read lines from one file and redirect them into another, if you wish.

The script I posted:

> verifies that three arguments are passed or dies. Remember that the Perl holds its first argument in $ARGV[0] unlike C.

> Uses the first argument as the user name variable, $name.

> Uses the second argument as the name of the template file, $tempf'. You can add or subtract lines to this file with changing the script.

> Slurps (reads into a variable named $template), the whole file named in the second argument ($tempf) passed.

> Replaces all matches to UUUUUU in $template with uppercase characters.

> Replaces all matches to uuuuuu in $template with lowercase characters.

> Uses the third argument passed to the script as the file that is to be read. This file is read and each line therein printed to STDOUT. If a line begins with 'ErrorLog', the $template string is printed *before* the line. All lines in the file are printed regardless.

If you would like to update your file in-place; that is, without redirecting the output to a file which you then rename to be that of the original input, change the first line of the script:

...from: #/usr/bin/perl

...to : $/usr/bin/perl -i.old

This will preserve a copy of the file you pass as the third argument as one with an extension of ".old" and perform an in-place modification for you.

Regards!

...JRF...
Unix or Linux?
Frequent Advisor

Re: Challenging script

James,

From what I understand of Perl I would say it meets some of the needs.

$template =~ s/UUUUUU/\U$name/g;
$template =~ s/uuuuuu/\L$name/g;

Correct me if i am incorrect, but this will only effect the user UUUUUU. The user could be called anything though. As I said, there are nine lines before
ErrorLog logs/error_log that need to be changed. When I run the script I will have no idea that the user at the last block of lines is called UUUUUU.

Should there not be a search for
ErrorLog logs/error_log first.

Copy these lines to the end of the file before ErrorLog logs/error_log
Then do the substitution.

So if I called the script with one parameter E.g. JOE

Then the result would be

Alias /BOB/block/ "/space/home/dir1/dir2/dir3/block/bob/block/"
Alias /BOB/doc/ "/space/home/dir1/dir2/dir3/block/bob/doc/"
Alias /BOB/out1/ "/space/home/dir1/dir2/dir3/block/bob/out1/"
Alias /BOB/out2/ "/space/home/dir1/dir2/dir3/block/bob/out2/"
Alias /BOB/out3/ "/space/home/dir1/dir2/dir3/block/bob/out2/out3/"
Alias /BOB/out4/ "/space/home/dir1/dir2/dir3/block/bob/out2/out4/"
Alias /BOB/test/out3/ "/space/home/dir1/dir2/dir3/block/bob/test/out3/"
Alias /BOB/test/out4/ "/space/home/dir1/dir2/dir3/block/bob/test/out4/"
Alias /BOB/out5/ "/space/home/dir1/dir2/dir3/block/bob/out5/"
Alias /JOE/block/ "/space/home/dir1/dir2/dir3/block/joe/block/"
Alias /JOE/doc/ "/space/home/dir1/dir2/dir3/block/joe/doc/"
Alias /JOE/out1/ "/space/home/dir1/dir2/dir3/block/joe/out1/"
Alias /JOE/out2/ "/space/home/dir1/dir2/dir3/block/joe/out2/"
Alias /JOE/out3/ "/space/home/dir1/dir2/dir3/block/joe/out2/out3/"
Alias /JOE/out4/ "/space/home/dir1/dir2/dir3/block/joe/out2/out4/"
Alias /JOE/test/out3/ "/space/home/dir1/dir2/dir3/block/joe/test/out3/"
Alias /JOE/test/out4/ "/space/home/dir1/dir2/dir3/block/joe/test/out4/"
Alias /JOE/out5/ "/space/home/dir1/dir2/dir3/block/joe/out5/"
ErrorLog logs/error_log

Hope this clarifies it! :)

Thanks
James R. Ferguson
Acclaimed Contributor

Re: Challenging script

Hi (again):

OK, trhy this:

# cat ./inserter
#!/usr/bin/perl
use strict;
use warnings;
die "Usage: $0 newname file\n" unless $#ARGV == 1;
my $newname = shift;
my ( $oldname, $marker, @lines );
while (<>) {
$marker = $_, next if /^ErrorLog/;
push @lines, $_;
print;
}
for (@lines) {
if (m%Alias /(.+?)/.+%) {
$oldname = $1;
s/$oldname/\U$newname/g;
$oldname = lc($oldname);
s/$oldname/\L$newname/g;
}
print;
}
print $marker;

...Run as:

# ./inserter newname file

...where "newname" is the value of the changed name and "file" is your input file.

Regards!

...JRF...
Sandman!
Honored Contributor

Re: Challenging script

Your last post clarified how the output should look like and based on that here's the script that does what you're looking for:

============================================================
#!/usr/bin/sh

LcaseUser=$(awk '/^Alias/ {split($2,z,"/");l=tolower(z[2])} END {print l}' $2)

User=$(awk '/^Alias/ {split($2,z,"/");u=z[2]} END {print u}' $2)

ex -s $2 <<-EOF
g/$User/ t /ErrorLog logs\/error_log/
/ErrorLog logs\/error_log/+1,$ s;/$User/;/\U$1/;g
/ErrorLog logs\/error_log/+1,$ s;/$LcaseUser/;/\L$1/;g
/ErrorLog logs\/error_log/ m $
wq
EOF
============================================================

execute as...

# <scriptname>

for example if the scriptname is "replace" and "BOB/bob" needs to be replaced with "JOE/joe" and the file to process is "infile" then invoke as follows:

# replace JOE infile
OR
# replace Joe infile
OR
# replace joe infile

replacement string can be case-free as script will take care of case conversion.

~cheers
Unix or Linux?
Frequent Advisor

Re: Challenging script

Sandman,

For some reason your script does not do anything!

#!/usr/bin/sh

LcaseUser=$(awk '/^Alias/ {split($2,z,"/");l=tolower(z[2])} END {print l}' $2)

User=$(awk '/^Alias/ {split($2,z,"/");u=z[2]} END {print u}' $2)

ex -s $2 <<-EOF
g/$User/ t /ErrorLog logs\/error_log/
/ErrorLog logs\/error_log/+1,$ s;/$User/;/\U$1/;g
/ErrorLog logs\/error_log/+1,$ s;/$LcaseUser/;/\L$1/;g
/ErrorLog logs\/error_log/ m $
wq
EOF


I am running it as follows

./change JOE file1

Where change is the name of the script
Sandman!
Honored Contributor

Re: Challenging script

I'm not sure why since it runs and produces the desired output on my machine. Did you check the contents of file1? Can you run it in debug mode and paste the output here.

# sh -x ./change JOE file1