Match a quoted string
Match a quoted string with a negated character class. An escaped quote inside the text ends the match early, and a PCRE alternation that pairs backslashes handles it.
Pulling the text between double quotes works until one of the strings contains an escaped quote.
line='say "hello" and "wor\"ld" end'
echo "$line" | grep -o '"[^"]*"'
echo ---
echo "$line" | grep -oP '"(?:[^"\\]|\\.)*"'"hello"
"wor\"
---
"hello"
"wor\"ld""[^"]*" reads an opening quote, as many non-quote characters as possible and a closing quote, so the quote after the backslash closes the second string and ld is left over. The second pattern takes either a character that is neither a quote nor a backslash, or a backslash followed by any character, which treats the escaped quote as part of the text. -P selects Perl-compatible expressions, as the GNU grep manual describes.
-P is not in POSIX grep and is missing from some builds, including the one that ships with macOS. The same pattern works as is in most languages. The match keeps the escape sequences, so unescape them afterwards. A quote that is doubled to escape itself, as in CSV, needs a different pattern, and for real CSV or JSON a parser is the better tool.