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.

13

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

  • Stephane, thanks for the answer man.. is grep -e '[^\]\\\\\\"' -e '^\\\\\\"' different from grep -e '[^\]\\\\\\"' ? Why do we need the second pattern argument? – Madhavan 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.... – Madhavan 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

Not the answer you're looking for? Browse other questions tagged or ask your own question.