How to Check If The Sed Command Replaced Some String

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.

How to check if the sed command replaced some string?

sed is not the right tool if you need to count the substitution, awk will fit better your needs :

awk -v OLD=foo -v NEW=bar '
($0 ~ OLD) {gsub(OLD, NEW); count++}1
END{print count " substitutions occured."}
' "$source_filename"

This latest solution counts only the number of lines substituted. The next snippet counts all substitutions with perl. This one has the advantage to be clearer than awk and we keep the syntax of sed substitution :

OLD=foo NEW=bar perl -pe '
$count += s/$ENV{OLD}/$ENV{NEW}/g;
END{print "$count substitutions occured.\n"}
' "$source_filename"

Edit

Thanks to william who had found the $count += s///g trick to count the number of substitutions (even or not on the same line)

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...

String not getting replaced with sed command

sed: -e expression #1, char 19: unterminated `s' command

Sure the s command is s/<something>/<else>/ - there is a trailing /. Do:

sed -r 's/where /$line ;/'
^ - trailing /

The -r option seems unused - where has no extended regular expressions. If so, remove it.

Your command uses ' quotes, so $line is not expanded. Research the difference between single and double quotes in shell, most probably you meant to use " here.

Note that each loop > qWithWhere.cql is recreating result and overwriting the result from previous loop. You might just run the loop on the last line them.

Read how to read a file line by line in bash and how to Escape a string for a sed replace pattern .


The following code with a space after where in input:

cat <<EOF >input
capture 'data.csv'
select * from test where
capture off;
EOF
line="where Column11 in ('Value1','Value2','Vlaue3') and Column12 in ('Value11','Value22','Vlaue32')"
sed -r "s/where /where $line ;/" input

outputs:

capture 'data.csv'
select * from test where where Column11 in ('Value1','Value2','Vlaue3') and Column12 in ('Value11','Value22','Vlaue32') ;
capture off;

Use sed command to check if a particular word exists, if not, add the word

You can use

#!/bin/bash

s='generic,daily,weekly,monthly
generic,daily,nightly,weekly,monthly'
markers=$(echo "$s" | sed -e "s/,/ and /g" -e "/nightly/!s/$/ and not nightly/")
echo "$markers"

Output:

generic and daily and weekly and monthly and not nightly
generic and daily and nightly and weekly and monthly

See the online demo. The /nightly/!s/$/ and not nightly/ does the following:

  • /nightly/! - skip a line if it contains nightly, else
  • s/$/ and not nightly/ - replace end of string with and not nightly.

Sed command to change a string at only desired place

Is there any way to replace the string using a WHERE clause so I can replace the string only where I want?

sed does not have SQL-style WHERE clauses, but commands can have "addresses" that define subsets of input lines to operate upon. These can take several forms. Regular expressions are perhaps the most common, but there are also line numbers, and a couple of special forms. You can also have inclusive ranges built from simple addresses. An address range would be a reasonably good way to address the problem you present.

For example,

sed -i '/^\s*-\s*stage:\s*Moto_Dev/,/^\s*-/ s/dependsOn: Build/dependsOn: Test/' input

Explanation:

  • The -i command-line flag tells sed to work "in-place", which really means that it will replace the original file with one containing sed's output.

  • The /^\s*-\s*stage:\s*Moto_Dev/,/^\s*-/ is a range address, consisting of a regex for the range start (/^\s*-\s*stage:\s*MotoDev/) and one for the range end (/^\s*-/).

    • /^\s*-\s*stage:\s*Moto_Dev/ matches the beginning of the section in which you want the change to be made, with some flexibility around the exact amount of whitespace at certain positions. For brevity and clarity, it uses \s to represent a single space or tab character. That is a GNU extension, but if you cannot depend on GNU sed then there are other ways to express the same thing.
    • /^\s*-/ matches the beginning of the next section, as you have presented the input. It could be made more specific if it were necessary to be more selective.
      The range includes its endpoints, but that does not appear to be a problem for the task at hand.
  • There is only one such range in the input presented, and that range contains the line you want to modify. The specified substitution, s/dependsOn: Build/dependsOn: Test/, is performed on each line in the range, but only the one contains a match to be replaced. All others in the range will be unaffected.

  • No commands at all are specified for lines outside the range, so they too will be unaffected.


You also asked,

I stored the desired piece of code in a variable. Can I use that
variable in a sed command? For example,

sed -i "s/condition: succeeded('Fair_PreProd')/condition: succeeded('Fair_UAT')/g" $folder_path/$file_name

sed does not expand shell-style parameter references, but you don't need it to do. The variable references in that command are expanded by the shell itself, before it executes the resulting command, so

  • yes, you may use them, and
  • it's not a question of using shell variables with sed in particular.


Related Topics



Leave a reply



Submit