Marilena
Marilena

Reputation: 33

sed replacing a string with warning when string not found

I want to change a line in a bunch of similar scripts using sed. Some of these scripts do not actually contain the line I want to change. However, sed doesn't tell me it didn't change the line cause it wasn't there. Any ideas on how I can make sed spit out a warning? Say, I have script one

    log export ALBET=0.155
    log export ALBEG=0.218
    log export RADGHGCOEF=1.0

and script two

    log export ALBET=0.168
    log export ALBEG=0.201

then

    sed -i 's/RADGHGCOEF=.*/RADGHGCOEF=2.0/' script

works on both on them, but I'd like to be informed that there was actually no line containing RADGHGCOEF to be changed in script 2. Thanks!

Upvotes: 3

Views: 792

Answers (4)

Walter A
Walter A

Reputation: 19982

Testing with grep before the sed (like @Sundeep suggested in a comment) is better than manipulating weird options of sed. This solution is just for fun:

You can let sed write something to stderr when it finds a string:

sed 's/RADGHGCOEF=.*/RADGHGCOEF=2.0/; /RADGHGCOEF/e echo yes >&2' script

I like to have it on stderr, avoiding it being written into the file when you add -i.
When you want to test the output, you want to convert stderr back to stdout.
Putting things together:

 test -z "$(sed -i 's/RADGHGCOEF=.*/RADGHGCOEF=2.0/;
                     /RADGHGCOEF/e echo yes >&2' script 2>&1)" && echo "Nothing found"

Upvotes: 1

Polar Bear
Polar Bear

Reputation: 6798

Code snippet to make desired replacement, default output to screen (final message printed to STDERR).

Run script with option -i for in-place replacement - perl -i script.pl file_name

use strict;
use warnings;
use feature 'say';

my $count;

while( <> ) {
    chomp;
    $count ++ if s/RADGHGCOEF=.*/RADGHGCOEF=2.0/;
    say;
}

if( $count ) {
    say STDERR "Info: replaced $count time(s)";
} else {
    say STDERR "Info: nothing to replace";
}

Input file some_data

log export ALBET=0.155
log export ALBEG=0.218
log export RADGHGCOEF=1.0

Run as ./script.pl some_data

log export ALBET=0.155
log export ALBEG=0.218
log export RADGHGCOEF=2.0
Info: replaced 1 time(s)

Run as perl -i script.pl some_data

Info: replaced 1 time(s)

Upvotes: 0

Timur Shtatland
Timur Shtatland

Reputation: 12337

Use this Perl one-liner:

perl -i -pe '$found++ if s/RADGHGCOEF=.*/RADGHGCOEF=2.0/; END { warn "$ARGV: not found\n" if !$found; }' script

The Perl one-liner uses these command line flags:
-e : Tells Perl to look for code in-line, instead of in a file.
-p : Loop over the input one line at a time, assigning it to $_ by default. Add print $_ after each loop iteration.
-i : Edit input files in-place (overwrite the input file).

$ARGV : current input file name.

$found++ if s/.../.../: increment by 1 the $found variable from its undef initial value, so that it now becomes 1 (or more, depending on how many times the substitution occurred).
END { ... } : execute the code after reading the entire input file. if !$found : if the substitution never occurred, $found is false in boolean context), otherwise true.

SEE ALSO:

perldoc perlrun: how to execute the Perl interpreter: command line switches
perldoc perlvar: Perl predefined variables

Upvotes: 5

anubhava
anubhava

Reputation: 784868

You can use this awk solution instead of sed:

awk '{n += sub(/RADGHGCOEF=.*/, "RADGHGCOEF=2.0")} 1; END{exit !n}' file &&
echo 'search string found!' || echo 'search string not found!'

This command will exit with 1 is substitutions occurred otherwise it wil exit with 0.

Upvotes: 4

Related Questions