14

The grep command gives out an exit status:

$echo "foo.bar" | grep -o foo
foo
$echo $?
0
$echo "foo.bar" | grep -o pop
$echo $?
1  

But I need to use sed and I realized that it has no exit status:

$echo "foo.bar" | sed 's/bar.*$//'
foo.
$echo $?
0
$echo "foo.bar" | sed 's/pop.*$//'
foo.bar
$echo $?
0  

I know that I should play around with the -q option, but I have not succeeded.

2
  • 8
    Note that sed most certainly does have an exit status, it just doesn't do what you need here. If the sed command fails, for example, if you try to run it on a file you don't have write access to or one that doesn't exist, sed will exit with a non-0 exit status. The exit status just indicates whether sed managed to do what you told it to do, and echo "foo.bar" | sed 's/pop.*$//' was correctly executed. It deleted all lines with pop. That there were no such lines is irrelevant, the command still worked.
    – terdon
    May 16, 2018 at 13:20
  • @Zanna I was going to post an answer, but I felt this doesn't actually answer the question. It only explains a misconception, but doesn't provide a helpful solution like steeldriver has below. So a comment seemed more appropriate.
    – terdon
    May 16, 2018 at 15:17

3 Answers 3

14

You can use qn to quit with exit status n - but to make that useful, you will also need to use some Branching and Flow Control:

t
branch conditionally (that is: jump to a label) only if a s/// command has succeeded since the last input line was read or another conditional branch was taken.

It is probably best to choose a value for n that is distinct from one of the standard exit status values:

An exit status of zero indicates success, and a nonzero value indicates failure. GNU 'sed' returns the following exit status error values:

0
 Successful completion.

1
 Invalid command, invalid syntax, invalid regular expression or a
 GNU 'sed' extension command used with '--posix'.

2
 One or more of the input file specified on the command line could
 not be opened (e.g.  if a file is not found, or read permission is
 denied).  Processing continued with other files.

4
 An I/O error, or a serious processing error during runtime, GNU
 'sed' aborted immediately.

So for example

$ echo "foo.bar" | sed 's/bar.*$//; t; q42' ; echo $? 
foo.
0

whereas

$ echo "foo.bar" | sed 's/baz.*$//; t; q42' ; echo $? 
foo.bar
42

If you want to omit the default printing of the pattern space, then replace q by Q (note that Q is a GNU extension).

1
  • 4
    Doesn't work for multiline file sed -i where replacement is somewhere i middle, only works for single-line patterns. Any idea how to use in a multiline file scenario?
    – lonix
    May 26, 2021 at 7:18
1

Here's how to search regex with sed, and highlight matches, or return exit code (5) if no match found:

This is input.txt:

hello there
my dear old friend
a lot of things
we'll pass along the end

Here's my function to Print all + Highlight matches + Return exit code:

highlight()
{
  pattern=$1
  shift
  sed '/'"${pattern}"'/,${s//\x1b[32m&\x1b[0m/g;b};$q5' "$@"
}

$ highlight "lo\|end" input.txt || echo -e "\n* No match found *"

hello there
my dear old friend
a lot of things
we'll pass along the end

When there's no match, it will return exit code (5). You can use it with cat and pipe | as well:

$ cat input.txt | highlight "hot\|and" || echo -e "\n* No match found *"

hello there
my dear old friend
a lot of things
we'll pass along the end

* No match found *

Thanks to https://unix.stackexchange.com/a/405725/43233 - I'm using it + sed quit option.

0

duplicate of answer https://stackoverflow.com/a/61808364/10440128

#!/bin/sh

read -d '' input <<EOF
a
b
EOF

echo "replace yes:"
echo "$input" >input.txt
sed -i 's/a/x/ w /dev/stdout' input.txt

echo "replace no:"
echo "$input" >input.txt
sed -i 's/z/x/ w /dev/stdout' input.txt

output:

replace yes:
x
replace no:

so, to check if sed did replace something:

#!/bin/sh

read -d '' input <<EOF
a
b
EOF

echo "$input" >input.txt
if [ -z "$(sed -i 's/a/x/w /dev/stdout' input.txt)" ]
then echo "replace no" # -z = "zero string"
else echo "replace yes"
fi

echo "$input" >input.txt
if [ -n "$(sed -i 's/z/x/w /dev/stdout' input.txt)" ]
then echo "replace yes" # -n = "nonzero string"
else echo "replace no"
fi

output:

replace yes
replace no

limitation: can handle only one substitution. so this does not work:

sed -i 's,a,b, w /dev/stdout ; s,b,a, w /dev/stdout' input.txt

error:

sed: couldn't open file /dev/stdout ; s,b,a, w /dev/stdout: No such file or directory

(sed treats everything after w as a file path)

workaround: use multiple sed calls

#!/bin/sh

read -d '' input <<EOF
a
b
EOF

echo "$input" >input.txt
if [ -n "$(
  sed -i 's/a/x/w /dev/stdout' input.txt &&
  sed -i 's/x/a/w /dev/stdout' input.txt
)" ]
then echo "replace yes"
else echo "replace no"
fi

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .