Return Value of Sed For No Match

Return value of sed for no match

as @cnicutar commented, the return code of a command means if the command was executed successfully. has nothing to do with the logic you implemented in the codes/scripts.

so if you have:

echo "foo"|sed '/bar/ s/a/b/'

sed will return 0 but if you write some syntax/expression errors, or the input/file doesn't exist, sed cannot execute your request, sed will return 1.

workaround

this is actually not workaround. sed has q command: (from man page):

 q [exit-code]

here you can define exit-code as you want. For example '/foo/!{q100}; {s/f/b/}' will exit with code 100 if foo isn't present, and otherwise perform the substitution f->b and exit with code 0.

Matched case:

kent$  echo "foo" | sed  '/foo/!{q100}; {s/f/b/}'
boo
kent$ echo $?
0

Unmatched case:

kent$ echo "trash" | sed  '/foo/!{q100}; {s/f/b/}'
trash
kent$ echo $?
100

I hope this answers your question.

edit

I must add that, the above example is just for one-line processing. I don't know your exact requirement. when you want to get exit 1. one-line unmatched or the whole file. If whole file unmatching case, you may consider awk, or even do a grep before your text processing...

“How to fix ‘sed + grep no return status when no match’ error in shell”

#!/bin/sh -e

This set's the set -e flag. From posix shell set manual emphasis mine:

-e

When this option is on, if a simple command fails for any of the reasons listed in Consequences of Shell Errors or returns an exit
status value >0, and is not part of the compound list following a
while, until, or if keyword, and is not a part of an AND or OR list,
and is not a pipeline preceded by the ! reserved word, then the shell
shall immediately exit
.

From man grep:

Normally the exit status is 0 if a line is selected, 1 if no lines
were selected, and 2 if an error occurred.

As the command grep in the pipeline inside a command substitution returns a non-zero status:

x=`
eval sed -n -e '1,"$"p' test.txt | # will not print any googoog
grep "googoo" # thus this will return with 1
` # command substitution exit status is the exit status of the last command executed
# the last command executed is grep - so command's substitution exit status is 1
# the exit status of variable assignment is the exit status of the last command executed
# the last command executed is command substitution - it's exit status was 1

The command returns with nonzero status, which terminates your script.

Notes:

  • Eval is evil, unneeded there, and using it is bad. Just sed -n -e '1,'"$p" test.txt...
  • Using backticks is deprecated. Don't use backticks. Use $( ... ), which looks cleaner, more readable, allows for nesting.
  • Remember about -e shell flag. Use it wise and learn to handle exit statuses from commands.

regexp (sed) suppress no match output

sed by default prints all lines.

What you want to do is

/patt/!d;s//repl/

IOW delete lines not matching your pattern, and if they match, extract particular element from it, giving capturing group number for instance. In your case it will be:

sed -e '/^.*\(.\)\([0-9][0-9]\)\1.*$/!d;s//\2/'

You can also use -n option to suppress echoing all lines. Then line is printed only when you explicitly state it. In practice scripts using -n are usually longer and more cumbersome to maintain. Here it will be:

sed -ne 's/^.*\(.\)\([0-9][0-9]\)\1.*$/\2/p'

There is also grep, but your example shows, why sed is sometimes better.

How to check if sed has changed a file

You could use awk instead:

awk '$0 ~ p { gsub(p, r); t=1} 1 END{ exit (!t) }' p="$pattern" r="$repl"

I'm ignoring the -i feature: you can use the shell do do redirections as necessary.

Sigh. Many comments below asking for basic tutorial on the shell. You can use the above command as follows:

if awk '$0 ~ p { gsub(p, r); t=1} 1 END{ exit (!t) }' \
p="$pattern" r="$repl" "$filename" > "${filename}.new"; then
cat "${filename}.new" > "${filename}"
# DO SOME OTHER STUFF HERE
else
# DO SOME OTHER STUFF HERE
fi

It is not clear to me if "DO SOME OTHER STUFF HERE" is the same in each case. Any similar code in the two blocks should be refactored accordingly.

Does sed have an option just for checking existence of string in file?

You can set the exit code using the q command in sed.

q [exit-code]

Immediately quit the sed script without processing any more input, except that if auto-print is not disabled the current pattern space
will be printed. The exit code argument is a GNU extension.

See also this answer for a clue.

EDIT:

As @cbuckley kindly linked to, you can find directions here.

sed is not showing exit status as other linux commands

The answer is "because that's how sed is implemented"

If you want to see if any changes were made

sed -i.bak -e 's/aa/AA/' file
if diff -q file file.bak >/dev/null; then
echo no changes
else
echo something changed
fi

Replace occurrences of a string in file with different bytes of entropy each

Instead of sed, you could use grep:

grep '<SECRET>' .env

From man grep:

EXIT STATUS

Normally the exit status is 0 if a line is selected, 1 if no lines were selected, and 2 if an error occurred. However, if the -q
or --quiet or --silent is
used and a line is selected, the exit status is 0 even if an error occurred.

If the return value is 0, then apply your sed command to perform the substitution.

Why sed is replacing all my file contents?

sed's default behavior if it isn't told to do anything else is to echo each line after running any commands that have been specified for it. So when you do sed -i ";" test.tex, it'll run ; on line 1, echo the (unchanged) line, and then move to line 2 and repeat the process. But if you do sed -i "q" test.tex, it makes the (total lack of) changes to line 1, echoes it, then runs the q command and exits immediately without having a chance to echo all the other lines.

That's what's happening in your code. To avoid that issue, you should specify a line range over which the q command will execute. $ is the last line, so:

sed -i "\@^@{ 1s@^@% Message\n@;}; $ {q100}" test.tex;


Related Topics



Leave a reply



Submit