0

I'm trying to understand a sed command shown on ETA Lab's Rich’s sh (POSIX shell) tricks page, specifically in the trick Shell-quoting arbitrary strings:

quote () { printf %s\\n "$1" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/'/" ; }

In the third sed command (\$s/\$/'/), I understand the first $ is escaped to prevent the shell to interpret it as a hypothetical $s variable, so it can be passed to sed and be rightfully interpreted as the last line address for the s command, but why escape the second $ ? Shouldn't it correctly match the end of the line as-is ?

MoonSweep
  • 428
  • 4
  • 11
  • 2
    probably because the dollar is special in double quotes, and escaping it is good hygiene. Then you don't need to think which ones of `!#%&/?_-` etc. require you to escape the preceding dollar, and if e.g. `$/` was only an existing special variable in Perl, or in the shell too... What if some future shell decided to add that as a non-standard special parameter? – ilkkachu Mar 02 '23 at 21:38
  • That sed command is unnecessarily complicated by escapes due to using double quotes instead of single quotes around the whole script instead of just using `'\''` or `\047` or `\27` or similar for the single quotes inside the script. Similarly for the printf formatting string - instead of having it unqupoted and requiring doubling uyp on escapes, `printf %s\\n "$1"` just quote it - `printf '%s\n' "$1"` – Ed Morton Mar 03 '23 at 16:40
  • 1
    That whole script is also redundant given `printf '%q\n' "$1"` or `printf '%s\n' "${1@Q}"` if your shell supports those constructs. – Ed Morton Mar 03 '23 at 16:59
  • 1
    @EdMorton "If your shell supports those constructs"... I think you didn't understand that the whole point of this page is to use only POSIX shell. `printf '%q\n'` or `${1@Q}` are not POSIX. – MoonSweep Mar 04 '23 at 00:09
  • @MoonSweep I did understand that this questions was asking about a web site that is about POSIX sh, but that doesn't mean everyone reading this NEEDS to only know about POSIX constructs and can't learn about better alternatives which is why I said `If your shell supports those constructs`. – Ed Morton Mar 04 '23 at 00:10
  • `$s` is required to expand to the contents of the `s` variable, but `$/` is unspecified and could expand to anything as far as POSIX is concerned. I don't know of any current shell where `$/` expands to anything other than `$/` but future ones may. `$!`, `$@`, `$*`, `$-`, `$?` are already special in all Bourne-like shells, `$(` in Korn/POSIX ones. `$[` in bash/zsh, `$^`, `$+`, `$~`, `$=` in zsh. `\$/` is specified by POSIX where the backslash is required to escape the `$`. – Stéphane Chazelas Mar 06 '23 at 15:09
  • @EdMorton, those aren't necessarily better as they're potentially unsafe. See [Escape a variable for use as content of another script](https://unix.stackexchange.com/a/600214) – Stéphane Chazelas Mar 06 '23 at 15:11

1 Answers1

1

You only need to escape the $ at the end of a regular expressions in an sed command to make it literal instead of being the end of the line.

Your sed command does not have any escaped $, because the backslashes are eaten by the shell. The command as it is seen by sed is just $s/$/'/ (in the last line, add a single quote to the end of the line).

So in the end, the title of your question is wrong: It's about shell escaping, not sed escaping.

Philippos
  • 13,237
  • 2
  • 37
  • 76
  • I didn't say that the question was _about `sed` escaping_, but that the escape was _in `sed` command_. But I'm not sure your answer is correct, because without the backslash, the second `$` would still correctly be interpreted by `sed`, since `$/` is not a reserved variable in POSIX. My question was about why this second `$` was escaped, whereas it seems at first glance that there's no need to. – MoonSweep Mar 26 '23 at 11:34