4

I have a json string inside json. This got encoded multiple times and I ended up with many escape backlashes: \\\".

The much shortened string looks like,

'[{"testId" : "12345", "message": "\\\"the status is pass\\\" comment \\\\\"this is some weird encoding\\\\\""}]'

I am trying to grep and get the number of occurrences of the pattern \\\" and not \\\\\"?

How can I do it?

Any shell/python solution is good to go. In python, using the search string

search_string = r"""\\\\\""", throws unexpected EOF error.

12

To look for \\\" anywhere on a line:

grep -F '\\\"'

That is, use -F for a fixed string search as opposed to a regular expression match (where backslash is special). And use strong quotes ('...') inside which backslash is not special.

Without -F, you'd need to double the backslashes:

grep '\\\\\\"'

Or use:

grep '\\\{3\}"'
grep -E '\\{3}"'
grep -E '[\]{3}"'

Within double quotes, you'd need another level of backslashes and also escape the " with backslash:

#              1
#     1234567890123
grep "\\\\\\\\\\\\\""

backslash is another shell quoting operator. So you can also quote those backslash and " characters with backslash:

\g\r\e\p \\\\\\\\\\\\\"

I've even quoted the characters of grep above though that's not necessary (as none of g, r, e, p are special to the shell (except in the Bourne shell if they appear in $IFS). The only character I've not quoted is the space character, as we do need its special meaning in the shell: separate arguments.

To look for \\\" provided it's not preceded by another backslash

grep -e '^\\\\\\"' -e '[^\]\\\\\\"'

That is, look for \\\" at the beginning of the line, or following a character other than backslash.

That time, we have to use a regular expression, a fixed-string search won't do.

grep returns the lines that match any of those expressions. You can also write it with one expression per line:

grep '^\\\\\\"
[^\]\\\\\\"'

Or with only one expression:

grep '^\(.*[^\]\)\{0,1\}\\\{3\}"' # BRE
grep -E '^(.*[^\])?\\{3}"'        # ERE equivalent
grep -E '(^|[^\])\\{3}"'

With GNU grep built with PCRE support, you can use a look-behind negative assertion:

grep -P '(?<!\\)\\{3}"'

Get a match count

To get a count of the lines that match the pattern (that is, that have one or more occurrences of \\\"), you'd add the -c option to grep. If however you want the number of occurrences, you can use the GNU specific -o option (though now also supported by a few other implementations) to print all the matches one per line, and then pipe to wc -l to get a line-count:

grep -Po '(?<!\\)\\{3}"' | wc -l

Or standardly/POSIXly, use awk instead:

awk '{n+=gsub(/(^|[^\\])\\{3}"/,"")};END{print 0+n}'

(awk's gsub() substitutes and returns the number of substitutions).

| improve this answer | |
  • Stephane, thanks for the answer man.. is grep -e '[^\]\\\\\\"' -e '^\\\\\\"' different from grep -e '[^\]\\\\\\"' ? Why do we need the second pattern argument? – user93868 Sep 10 '15 at 11:53
  • @MadhavanKumar, grep '[^\]\\\\\\"' would not match on a line that starts with \\\". As that line would not have that non-backslash character ([^\]) before \\\". The second expression looks for \\\" at the beginning of the line (^). – Stéphane Chazelas Sep 10 '15 at 11:55
  • yup... it solves it... it is an or pattern.... – user93868 Sep 10 '15 at 11:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy