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
  • 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 – 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,453
  • 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