1

is it possible to filter, i.e to put ESC in front of the inner quotes with sed, awk or other *NIX tool (no perl/python)?

Example (revised):

$ echo label=\"123 \"456\" 789\" \"AB C\" e f gh | magic-filter
label="123 \"456\" 789\" \"AB C" e f gh

label="123 \"456\" 789" "AB C"

In other words a filter is needed that will filter in the following way: the first and last " char will be passed as is, but all other " will be replaced with \ followed by ".

closed as unclear what you're asking by Jeff Schaller, HalosGhost, techraf, strugee, Archemar Oct 24 '16 at 6:37

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 6
    By which rule is it possible to define which " is "internal"? You could have as well selected the first and the last as external and the rest as internal. There are several other alternative selections. – sorontar Oct 23 '16 at 18:40
  • 2
    That is correct remark! Let's assume all quotes between th 1st and last as inner. – ivand58 Oct 23 '16 at 19:13
  • @ivand58 you should edit your question to include that information. – strugee Oct 24 '16 at 1:32
1

With GNU sed, which supports replacing all occurrences from particular count

$ echo label=\"123 \"456\" 789\" \"AB C\" e f gh | 
    sed -E 's/"/\\"/2g; s/\\("[^"]*)$/\1/'
label="123 \"456\" 789\" \"AB C" e f gh

All " (expect first ") are replaced with \" and then \ is removed from last \"


If GNU sed is not available, remove \ from first \" as well

$ echo label=\"123 \"456\" 789\" \"AB C\" e f gh | 
    sed -E 's/"/\\"/g; s/\\"/"/; s/\\("[^"]*)$/\1/'
label="123 \"456\" 789\" \"AB C" e f gh

Note: Some sed versions might need -r instead of -E


With perl

$ echo label=\"123 \"456\" 789\" \"AB C\" e f gh | 
    perl -pe 's/(^[^"]*"|"[^"]*$)(*SKIP)(*F)|"/\\"/g'
label="123 \"456\" 789\" \"AB C" e f gh

Here, the string up to first " and string from last " to end of line are skipped while the remaining " are replaced with \"

1

sed to the rescue.

sed 's/"/\x1b"/g;s/\x1b"/"/;s/\(.*\)\x1b"/\1"/'

Replace all quotes with ESC" and then revisit and replace first with just quote, and replace final with just quote. Detailed explanation:

  • s/"/\x1b"/g : replace all quote characters with \x1b (ESC) and quote.

  • s/\x1b"/"/ : replace first \x1b (ESC) and quote combination with single quote.

  • s/\(.*\)\x1b"/\1"/ : replace final \x1b (ESC) and quote combination with single quote

Example output:

$ echo label=\"123 \"456\" 789\" \"AB C\" e f gh |sed 's/"/\x1b"/g;s/\x1b"/"/;s/\(.*\)\x1b"/\1"/'|od -c
0000000   l   a   b   e   l   =   "   1   2   3     033   "   4   5   6
0000020 033   "       7   8   9 033   "     033   "   A   B       C   "
0000040       e       f       g   h  \n
0000050
$
  • the problem is not in the echo, I looking for a filter. Here the echo part is given for illustration a test case – ivand58 Oct 23 '16 at 19:22
0

There is a way to get what you ask for in several steps:
Assuming a variable could contain the string (the string doesn't have single quotes):

$ label='label=\"123 \"456\" 789\" \"AB C\" e f gh'

We could chop out the part after the \":

$ front=${label%\\\"*}
$ echo "$front"
\"123 \"456\" 789\" \"AB C

Then remove up to the first \":

$ mid=${front#*\"}
$ echo "$mid"
123 \"456\" 789\" \"AB C

Replace all \" by \e":

$ final=${mid//\\\"/\\e}
$ echo "$final"
123 \e456\e 789\e \eAB C

And finally, reconstruct the original string and use printf for the escapes:

$ printf "label=\"${front%%\\\"*}$final\"${label#"${front}"}\n"
label="123 456 789 AB C"" e f gh

$ printf "label=\"${front%%\\\"*}$final\"${label#"${front}"}\n" | od -vAn -t x1c
  6c  61  62  65  6c  3d  22  31  32  33  20  1b  22  34  35  36
   l   a   b   e   l   =   "   1   2   3     033   "   4   5   6
  1b  22  20  37  38  39  1b  22  20  1b  22  41  42  20  43  22
 033   "       7   8   9 033   "     033   "   A   B       C   "
  22  20  65  20  66  20  67  68  0a
   "       e       f       g   h  \n

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