简体   繁体   中英

Replace a line in a text file using sed but keeping \ as part of the replacement line from perl script

What I need done is to replace a line in a file from perl using a sed command. The issue is the line I need to put into the file has \\ in several places and I have not figured out how to kepp the \\ without perl/sed removing them.

Example is :

system sed "s/^destinaion=.*/destination=Manager {manager hostname\=$NAME,Manager port\=8443} $USER_NAME/" -i /usr/local/example_file.txt;

In the file I get:

destination=Manager {manager hostname=Bill,Manager port=8443} Fred

I need to get in the file :

destination=Manager {manager hostname\=Bill,Manager port\=8443} Fred

This is a properties file for configuration and it needs to be exact.

Using this site I came up with the following solution that works for me:

My command in perl (Just an Example):

$VAR1=$NAME

$VAR2=$USER_NAME

$VAR3='destination=Manager {manager hostname\\\\'

$VAR4='Manager port\\\\=8443} '

system sed 's/^destinaion=.*/$VAR3=$VAR1,$VAR4 $VAR2/' -i 
/usr/local/example_file.txt;

Output was :

destination=Manager {manager hostname\=Bill,Manager port\=8443} Fred

This worked as I am passing the same line to 4 different property files depending on the answers to the question and the redhat version. The software I am installing has different property files depending on which redhat version is in use. I have to create the property files by doing one install then I change the property file in my script and do an install on all the servers with a foreach so I can run the script and then watch for errors.

We are currently using two versions so I have had to add if statements in my script to select the correct property files.

As noted in a comment:

It's tricky; you have to work out how many processes are interpreting the string and removing backslashes. To put a single backslash into the output, sed needs to see two consecutive backslashes in the replacement portion of the s/…/…/ operation. Since you enclose that in double quotes, Perl gets a chance to interpret the backslashes too; that means you need 4 backslashes in the Perl for each one in the output.

Because you're using the 'array' notation for the system call (except the syntax is wrong — you need commas between the items, and quotes around the plain words), you avoid having a shell interpret the string too.

This works for me on macOS Sierra 10.12.2 and should work with GNU sed too (renaming the file to data ):

#!/usr/bin/perl

use strict;
use warnings;

my $NAME = "Alexander";
my $USER_NAME = "The Great";
system "sed", "-e", "s/^destinaion=.*/destination=Manager {manager hostname\\\\=$NAME,Manager port\\\\=8443} $USER_NAME/", "-i.bak", "data";

File data before:

##destinaion=Manager {manager hostname=Bill,Manager port=8443} Fred
destinaion=Manager {manager hostname=Bill,Manager port=8443} Fred

File data after:

##destinaion=Manager {manager hostname=Bill,Manager port=8443} Fred
destination=Manager {manager hostname\=Alexander,Manager port\=8443} The Great

Here's a variant script that shows how different numbers of backslashes are needed. The example with 8 backslashes in a row has Perl halve the number to 4, the shell halve the number to 2, and sed interpret the 2 as meaning 1 in the output. When you see 8 backslashes in a row, you can be pretty confident that you're not dealing with something in the best possible way. (In the days of yore, sometimes a troff file would have 16 backslashes in a row, but not often, and very few people understood why when they were necessary.)

#!/usr/bin/perl

use strict;
use warnings;

my $NAME = "Alexander";
my $USER_NAME = "The Great";
system "sed", "-e", "s/^D1=.*/destination1=Manager {manager hostname\\\\=$NAME,Manager port\\\\=8443} $USER_NAME/", "-i.bak", "data";
system "sed -e \"s/^D2=.*/destination2=Manager {manager hostname\\\\\\\\=$NAME,Manager port\\\\\\\\=8443} $USER_NAME/\" -i.bak data";
system "sed -e 's/^D3=.*/destination3=Manager {manager hostname\\\\=$NAME,Manager port\\\\=8443} $USER_NAME/' -i.bak data";

Here's the initial variant data file:

D1=Manager {manager hostname=Bill,Manager port=8443} Fred
D2=Manager {manager hostname=Bill,Manager port=8443} Fred
D3=Manager {manager hostname=Bill,Manager port=8443} Fred

Here's the result of running the variant script on the variant data file:

destination1=Manager {manager hostname\=Alexander,Manager port\=8443} The Great
destination2=Manager {manager hostname\=Alexander,Manager port\=8443} The Great
destination3=Manager {manager hostname\=Alexander,Manager port\=8443} The Great

If you didn't need $NAME and $USER_NAME expanded, there could be another variant with single quotes around the s/…/…/ command in the array notation; it would only need two backslashes, not four.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM