2

I have some awk that rearrange a line. I would like to escape one of the variables (e.g. $_), in such way that " and \ are escaped with a backslash.

Example:

echo "Ehm, \"hi\", he \\ said" | awk '{$1="" ; print "\"" $_ "\"" }'
" "hi", he \ said"

(do not change the echo, normally I read from a file that has Ehm, "hi", he \ said in it).

I would like to have

" \"hi\", he \\ said" 

instead. How can I do this? Is there a function in awk that can do this?

Peter Smit
  • 27,696
  • 33
  • 111
  • 170
  • 1
    What is `$_` in the context of an awk program? – Tom Fenech Aug 24 '16 at 09:17
  • @Tom that means, rest of the line – Peter Smit Aug 24 '16 at 09:19
  • 1
    As mentioned in answers to [this question](http://stackoverflow.com/q/6293790/2088135), it looks like `$_` ends up working because `_` evaluates to `0`, so you end up with `$0`. It is not typical to see `$_` in awk scripts. Use `$0` to refer to the whole line. – Tom Fenech Aug 24 '16 at 09:23
  • I think you should decouple the part of `$1=""`, because it is generating noise. Unless it is strictly necessary, the question would benefit from it. Also, from your update it looks like you just want to add `\` to any `"` or `\` found in the string, isn't it the case at the end? – fedorqui Aug 24 '16 at 09:39
  • @fedorqui Your comment was not marked up well, as I can't understand what you have written – Peter Smit Aug 24 '16 at 09:45
  • Wops, sorry! I wanted to say: from your update, it looks like you just want to add \ to any `"` or \ found in the string. In that case, `gawk '{print gensub(/("|\\)/, "\\\\\\1", "g")}' file` would make it. – fedorqui Aug 24 '16 at 09:47
  • Your question seems rather confusing, are you asking: "How can I replace characters in a string?" – Micha Wiedenmann Aug 24 '16 at 11:49

3 Answers3

2

Is this what you're looking for?

$ cat tst.awk
function foo(str) {
    sub(/^[^[:space:]]+/,"",str)   # remove first field
    gsub(/["\\]/,"\\\\&",str)      # put \ before each \ and "
    return "\"" str "\""           # surround with quotes
}
{ print foo($0) }

Test:

$ echo "Ehm, \"hi\", he \\ said" | awk -f tst.awk
" \"hi\", he \\ said"

$ cat file
Ehm, "hi", he \ said

$ awk -f tst.awk file
" \"hi\", he \\ said"
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
1

When you pass a string with Bash, you have to take into consideration what echo itself is performing with the double quotes. Find it here:

$ echo "Ehm, \"hi\", he \\ said" | awk '1'
Ehm, "hi", he \ said

Using single quotes solves part of the problem:

$ echo 'Ehm, \"hi\", he \\ said' | awk '1'
Ehm, \"hi\", he \\ said

This being said, now it is time to add quotes around the string. For this, we use print with three arguments --> print "\"", $0, "\"".

To remove the first field, we can do it in the correct way:

$ echo 'Ehm, \"hi\", he \\ said' | awk '{sub(/^\S+\s*/, ""); print "\"", $0, "\""}'
"\"hi\", he \\ said"

If we just blank it, it looks like we get what your desired output was:

$ echo 'Ehm, \"hi\", he \\ said' | awk '{$1=""; print "\"", $0, "\""}'
" \"hi\", he \\ said"
Community
  • 1
  • 1
fedorqui
  • 275,237
  • 103
  • 548
  • 598
  • Why use `sprintf` and then add `1` to print, when you can just use `printf` (or even just `print`)? – Tom Fenech Aug 24 '16 at 09:29
  • The echo was only an example, normally `Ehm, "hi", he \ said` is in the file that awk processes. The awk doesn't escape anything of the original variable at the moment – Peter Smit Aug 24 '16 at 09:32
  • @TomFenech ha! Because I was too much into changing the string that I lost focus :D – fedorqui Aug 24 '16 at 09:32
  • 1
    @PeterSmit then you should edit your original question to make it more representative. – fedorqui Aug 24 '16 at 09:33
  • I specifically asked in the question for a function in awk to do the escaping, but I'll clarify it more – Peter Smit Aug 24 '16 at 09:34
1

Is there a reason you resort to awk? Bash is perfectly able to perform string manipulations:

#!/bin/bash

read -r ignored line <<<'Ehm, "hi", he \ said'
line=${line//\\/\\\\}
line=${line//\"/\\\"}
echo $line

Output

\"hi\", he \\ said
Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137