4

The content of my input file is shown below:

abc\**def\ghi**\abc\!!!!!
abc\**4nfiug\frgrefd\gtefe\wf4fs**\abc\df3gwddw
abc\**eg4/refw**\abc\f3

I need to replace whatever string in between abc \ --------------\abc in my input file with ABC\CBA.

I have tried something like below to get the strings that need to be replaced. But I get stuck when I need to use the search and replace:

my $string1 = qr/abc\W+([^a]+)/;
my $string2 = map{/$string1/ => " "} @input_file; # The string that needs to be replaced
my $string3 = 'ABC\CBA'  # String in that. I want it to replace to

s/$string2/$string3/g

How can I fix this?

5 Answers 5

13
perl -i -pe 's/this/that/g;'  file1
Sign up to request clarification or add additional context in comments.

4 Comments

To avoid all the escape characters and improve code readability (avoiding the "Leaning Toothpick Syndrom": en.wikipedia.org/wiki/Leaning_toothpick_syndrome), you can also replace the "/" delimiters/separators by a hashtag "#" ===> perl -i -pe 's#this#that#g;' file1
An explanation would be in order. E.g., is the magic in -i and/or -p? And why?
The -i flag here means "in place editing". Perl does this under the hood by creating a temp-file with the results and later renaming that file to the name of the original.
2

A one-liner to fix a file:

perl -plwe 's/abc\\\K.*(?=\\abc)/ABC\\CBA/' input.txt > output.txt

Or as a script:

use strict;
use warnings;

while (<DATA>) {
    s/abc\\\K.*(?=\\abc)/ABC\\CBA/;
    print;
}

__DATA__
abc\**def\ghi**\abc\!!!!!
abc\**4nfiug\frgrefd\gtefe\wf4fs**\abc\df3gwddw
abc\**eg4/refw**\abc\f3

The \K (keep) escape sequence means these characters will not be removed. Similarly, the look-ahead assertion (?= ... ) will keep that part of the match. I assumed you only wanted to change the characters in between.

Instead of \K one can use a look-behind assertion: (?<=abc\\). As a personal preference, I used \K instead.

Comments

1
#!/usr/bin/perl
use strict;
use warnings;

open my $fh,"<", "tryit.txt" or die $!;

while (my $line = <$fh>) {
    $line =~ s/(abc\\)(.*?)(\\abc)/$1ABC\\CBA$3/;
    print $line;
}

gives the following with the input data.

abc\ABC\CBA\abc\!!!!!
abc\ABC\CBA\abc\df3gwddw
abc\ABC\CBA\abc\f3

4 Comments

Thanks Mike.This is almost what I want.The results printed on the unix is what I want.However, I need to overwrite my input file with the result obtained.FYI, my input file is still the same before and after executing the script.
There's dozens of ways to do this depending on how often this needs to be used. The easiest was (in my opinion), is to write the output to a temp file, delete the original, and then rename the temp to the original input file name.
Based on @TLP's edits, I'm guessing my methods are old school :-P
@steven You can use the -i switch from the command line to do in-place edit.
1

If you do not want the substitution to operate on the default variable $_, you have to use the =~ operator:

#!/usr/bin/perl
use warnings;
use strict;

my @input_file = split /\n/, <<'__EOF__';
abc\**def\ghi**\abc\!!!!!
abc\**4nfiug\frgrefd\gtefe\wf4fs**\abc\df3gwddw
abc\**eg4/refw**\abc\f3
__EOF__

my $pattern = qr/abc\\.*\\abc/;       # pattern to be matched
my $string2 = join "\n", @input_file; # the string that need to be replaced
my $string3 = 'ABC\CBA';              # string i that i want it to replace to

$string2 =~ s/$pattern/$string3/g;
print $string2;

3 Comments

Thanks choroba. I have tried to open my file and do all the searching and replacing.however, it seems lk no effect on my input file. i have tried below: foreach my $file ($input) { open(I,$file) or die $!; <I>; while(<I>) { my $pattern = qr/abc\\.*\\abc/;my $string2 = join "\n", @input_file;my $string3 = 'ABC\CBA';$string2 =~ s/$pattern/$string3/g; print $string2; } close(I) }
Why do you first split on newline, then join that split with newline? Seems redundant.
@TLP: If you asked me, I just wanted to use @input_file as the author of the question.
1

To address your comment about replacing text "inplace" in the file directly, you can use the -i switch for a one-liner. In a script, you can perhaps look at using Tie::File, which allows read-write access to lines of a file as (mutable) elements in an array. To copy Mike/TLP's answer:

#!/usr/bin/perl
use strict;
use warnings;

use Tie::File;

tie my @file, "Tie::File", "tryit.txt" or die $!;

# I think you have to use $_ here (done implicitly)
while (@file) {
    s/(abc\\)(.*?)(\\abc)/$1ABC\\CBA$3/;
    print;
}

1 Comment

Use for instead of while, and the print isn't necessary as Tie::File will update the file. (a colleague of mine have got a CopyPasteInheritance bug from this code snippet ^^)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.