Operating System - Linux
1752423 Members
4829 Online
108788 Solutions
New Discussion юеВ

Re: Replace string in place..retain original line.

 
SOLVED
Go to solution
OFC_EDM
Respected Contributor

Replace string in place..retain original line.

This question stems from a solution I got from James R Ferguson. Thanks James!

Where the following command replaces a string and backs up the file before the update.

perl -pi.old -e 's/\bDISABLETIME=\d\d\b/DISABLETIME=60/' ./login

I want to customize this further:

In the login file the line may be
#DISABLETIME=20
#DISABLETIME=100
#DISABLETIME=2000

If I find any one or other variations I want to leave the commented out line.

Then add a new line
DISABLETIME=60
after the original line.

Thereby leaving the original value in place in case I need to go back to it.

So it may look like:
#DISABLETIME=200
DISABLETIME=60
After the update is done.

How can the perl command be modified to do this?

Regards
The Devil is in the detail.
13 REPLIES 13
OFC_EDM
Respected Contributor

Re: Replace string in place..retain original line.

I figured out part of this

perl -pi.old -e 's/\bDISABLETIME=[0-9]*\b/\nDISABLETIME=60/g' ./login.test

Will put in the newline and my new value of DISABLETIME=60.

But it won't retain the original line.

Maybe there's a way to reference the original string in the replacement string?
The Devil is in the detail.
Dennis Handly
Acclaimed Contributor

Re: Replace string in place..retain original line.

>In the login file the line may be

These lines start with "#"?

>If I find any one or other variations I want to leave the commented out line.
>Thereby leaving the original value in place in case I need to go back to it.

You need to provide more details. Are the lines already commended out or do you want to comment them out, then add the "=60" line?
Do you only have the one?

You might be able to use sed but it is easier to use awk:
$ awk '
/DISABLETIME=/ {
print $0
print "DISABLETIME=60"
}
{
print $0
}' login > login.new
OFC_EDM
Respected Contributor

Re: Replace string in place..retain original line.

I'm updating over 100 servers.

Some already have the DISABLETIME=60 in place and some won't.

Some will already have it commented out. And I won't know the value after the = sign.

So I have to handle both those conditions:
Regardless I want the original line to end up being commented out.

And append the new DISABLETIME=60 line immediately after the original

I want to try and stick with the perl statement as it automatically backs up the file.

Another reason is I'm trying to convert myself to Perl :)
The Devil is in the detail.
James R. Ferguson
Acclaimed Contributor

Re: Replace string in place..retain original line.

Hi:

# perl -ni.old -e 'print;if m/#\s*DISABLETIME\s*=\s*\d+/) {print "DISABLETIME=60\n"}' file

...which would handle patterns like:

#DISABLETIME=20

# DISABLETIME = 2000

Regards!

...JRF...
OFC_EDM
Respected Contributor

Re: Replace string in place..retain original line.

Thanks James,

Did I put the code in incorrectly? I get the error below.

perl -ni.old -e 'print;if m/#\s*DISABLETIME\s*=\s*\d+/) {print "DISABLETIME=60\n"}' ./login.test


syntax error at -e line 1, near "if m/#\s*DISABLETIME\s*=\s*\d+/"
syntax error at -e line 1, near ";}"
Execution of -e aborted due to compilation errors.

Would you mind explaining how the command works?

I think the \s* matches all white space from the next to the end of the line (before newline character).

And \d+ is one or more digits.

Whats the m at the beginning?

Am I interpreting the command correctly as follows?:
print the line, match the string, apply condition and then print if condition met?

Thanks again
The Devil is in the detail.
James R. Ferguson
Acclaimed Contributor
Solution

Re: Replace string in place..retain original line.

Hi (again):

Sorry, mMy error; I dropped the opening parenthesis:

# perl -ni.old -e 'print;if (m/#\s*DISABLETIME\s*=\s*\d+/) {print "DISABLETIME=60\n"}' ./login.test

The '\s*' means zero or more whitespace (blank, tab, newline and carriage-return) characters.

The '\d+' means one or more digits. Note the '+' versus the '*' for one-or-more versus zero-or-more.

The 'm' in this context is optional, but means "match". With a forward slash '/' as a delimiter, 'm' is inferred. Other delimiters can be used for clarity and that's when the leading 'm' is really needed. I could have written:

# perl -ni.old -e 'print;if (m{#\s*DISABLETIME\s*=\s*\d+}) {print "DISABLETIME=60\n"}' ./login.test

...that is, used '{' and '}' as the matching delimiters. This is very useful when you want to avoid the "leaning toothpick syndrome", like:

# if ( m/\/usr\/bin\/sh/ ) ...

...becomes:

# if ( m{/usr/bin/sh} ) ...

Regards!

...JRF...
OFC_EDM
Respected Contributor

Re: Replace string in place..retain original line.

James,

I've hit a snag where some login files for some systems have previous commented out values.

Which results in multiple line matches.

I just want to insert my DISABLETIME=60 after the LAST match

Example:

# DISABLETIME=20
# DISABLETIME=100
DISABLETIME=60 <---Insert here

Unfortunately my code does this:
# DISABLETIME=20
DISABLETIME=60 <---Inserts here
# DISABLETIME=100
DISABLETIME=60 <---and Inserts here

I run the following:
# Find any lines uncommented and comment out
perl -pi.old -e 's/^DISABLETIME=\s*/#DISABLETIME=/g' ${dwnld_dir}/login.${TARGET}

# Find LAST commented line and insert new line
perl -ni -e 'print;if (m/#\s*DISABLETIME\s*=\s*\d+/) {print "DISABLETIME=60\n"}' ${dwnld_dir}/login.${TARGET}

Any ideas on how to improve the code?
The Devil is in the detail.
James R. Ferguson
Acclaimed Contributor

Re: Replace string in place..retain original line.

Hi (again):

Ok, given a configuration file like this:

# cat ./myconfig
this is a some config file...
# DISABLETIME=20
# DISABLETIME= 200
#DISABLETIME=1000
DISABLETIME=60
this is more of the file
and this is still more of the file

...Use this script:

# cat ./myfilter
#!/usr/bin/perl -i.old
use strict;
use warnings;
my $lines = do { local $/ = undef; <> };
$lines =~ s/( \#\s*DISABLETIME\s*=\d+.+?$ ) (?! \s*\#\s*DISABLETIME ) /$1\nDISABLETIME=60/smx;
print $lines;
1;

...and thus:

# ./myfilter ./myconfig

...yields a modified './myconfig' [with a backup as '*.old'] of:

this is a some config file...
# DISABLETIME=20
# DISABLETIME= 200
#DISABLETIME=1000
DISABLETIME=60
this is more of the file
and this is still more of the file

Regards!

...JRF...
OFC_EDM
Respected Contributor

Re: Replace string in place..retain original line.

Thanks (again) James.

But I think I have a perl issue.
I try to run the code and get this.
I assume it means I don't have a module called warnings.pm on the system.
And I can't update the perl install there.

=>./myfilter ./retrievedfiles/login.iecs
Can't locate warnings.pm in @INC (@INC contains: /usr/perl5/5.00503/sun4-solaris /usr/perl5/5.00503 /usr/perl5/site_perl/5.005/sun4-solaris /usr/perl5/site_perl/5.005 .) at ./myfilter line 3.
BEGIN failed--compilation aborted at ./myfilter line 3.
The Devil is in the detail.