Re: Challenging script (71 Views)
Reply
Frequent Advisor
Unix or Linux?
Posts: 50
Registered: ‎04-17-2006
Message 1 of 18 (71 Views)

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
Please use plain text.
Acclaimed Contributor
James R. Ferguson
Posts: 21,184
Registered: ‎07-06-2000
Message 2 of 18 (71 Views)

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...
Please use plain text.
Frequent Advisor
Unix or Linux?
Posts: 50
Registered: ‎04-17-2006
Message 3 of 18 (71 Views)

Re: Challenging script

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

Please use plain text.
Honored Contributor
Sandman!
Posts: 2,220
Registered: ‎01-13-2005
Message 4 of 18 (71 Views)

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!
Please use plain text.
Acclaimed Contributor
James R. Ferguson
Posts: 21,184
Registered: ‎07-06-2000
Message 5 of 18 (71 Views)

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...
Please use plain text.
Frequent Advisor
Unix or Linux?
Posts: 50
Registered: ‎04-17-2006
Message 6 of 18 (71 Views)

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
Please use plain text.
Acclaimed Contributor
James R. Ferguson
Posts: 21,184
Registered: ‎07-06-2000
Message 7 of 18 (71 Views)

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...
Please use plain text.
Honored Contributor
Sandman!
Posts: 2,220
Registered: ‎01-13-2005
Message 8 of 18 (71 Views)

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
Please use plain text.
Frequent Advisor
Unix or Linux?
Posts: 50
Registered: ‎04-17-2006
Message 9 of 18 (71 Views)

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
Please use plain text.
Honored Contributor
Sandman!
Posts: 2,220
Registered: ‎01-13-2005
Message 10 of 18 (71 Views)

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
Please use plain text.
Honored Contributor
Sandman!
Posts: 2,220
Registered: ‎01-13-2005
Message 11 of 18 (71 Views)

Re: Challenging script

Updated script pasted below since the earlier one made an inverse copy of the block of lines that were to be changed. Execute as follows:

# ./change file1

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

UP=$(echo $1 | awk '{print toupper($0)}')
Usr=$(awk '/^Alias/ {split($2,z,"/");u=z[2]} END {print u}' $2)
LUsr=$(awk '/^Alias/ {split($2,z,"/");l=tolower(z[2])} END {print l}' $2)

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

hope it helps!
Please use plain text.
Frequent Advisor
Unix or Linux?
Posts: 50
Registered: ‎04-17-2006
Message 12 of 18 (71 Views)

Re: Challenging script

Sandman,

Whenever I try to run that script it gives the following error.

./change: syntax error at line 3: `UP=$' unexpected

Not sure where the syntax error is?
I have copied directly as you wrote it.

Thanks
Please use plain text.
Honored Contributor
Sandman!
Posts: 2,220
Registered: ‎01-13-2005
Message 13 of 18 (71 Views)

Re: Challenging script

What OS version are you running? Run your script in debug mode and paste the output here for troubleshooting purposes.

# sh -x ./change

I'ave attached the script so that there are no invisible characters inserted into the shell script when you copy it.
Please use plain text.
Frequent Advisor
Unix or Linux?
Posts: 50
Registered: ‎04-17-2006
Message 14 of 18 (71 Views)

Re: Challenging script

Sorry about the delay. I had to modify the script slightly, as the Unix version I am running does not support the new POSIX standard that uses $() command. I used ` ` instead.

Using cat /etc/release for OS version

Solaris 8



$ sh -x ./change joe test2
+ awk + {print toupper($0)}
echo joe
UP=joe
+ awk /^Alias/ {split($2,z,"/");u=z[2]} END {print u} test2
Usr=BOB
+ awk /^Alias/ {split($2,z,"/");l=tolower(z[2])} END {print l} test2
LUsr=BOB
+ ex -s test2
g/BOB/ t /ErrorLog logs\/error_log/
/ErrorLog logs\/error_log/+1,$ s;/BOB/;/\Ujoe/;g
/ErrorLog logs\/error_log/+1,$ s;/BOB/;/\Ljoe/;g
g/\/joe\// m /ErrorLog logs\/error_log/
/ErrorLog logs\/error_log/ m $
wq
Substitute pattern match failed
Please use plain text.
Frequent Advisor
Unix or Linux?
Posts: 50
Registered: ‎04-17-2006
Message 15 of 18 (71 Views)

Re: Challenging script

Actually using:

uname -sr

SunOS 5.8
Please use plain text.
Honored Contributor
Sandman!
Posts: 2,220
Registered: ‎01-13-2005
Message 16 of 18 (71 Views)

Re: Challenging script

Hmmm...I thought you might not be on HP-UX as the awk command on HP is the new awk (nawk) while in Solaris it is still the old awk. So in order to make it work on Solaris you have to replace all invocations of awk with nawk.

~cheers

Please use plain text.
Frequent Advisor
Unix or Linux?
Posts: 50
Registered: ‎04-17-2006
Message 17 of 18 (71 Views)

Re: Challenging script

Thanks. Seems to work now. Thanks for the tip regarding awk with Solaris.
Please use plain text.
Frequent Advisor
Unix or Linux?
Posts: 50
Registered: ‎04-17-2006
Message 18 of 18 (71 Views)

Re: Challenging script

Sandman,

Could you give an explanation of the following


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 $


Please use plain text.
The opinions expressed above are the personal opinions of the authors, not of HP. By using this site, you accept the Terms of Use and Rules of Participation