How does the leading dollar sign affect single quotes in Bash?
Asked Answered
O

3

104

I need to pass a string to a program as its argument from the Bash CLI, e.g

program "don't do this"

The string may include any character like '$', '\', etc. and I don't want Bash to do any modification. So I think about using single quotes.

However the following does not work:

 program 'don\'t do this'            //escape doesn't work in single quote

While the following two works:

 program $'dont\'t do this'          //seems fine, but any other side effects?
 program 'dont'\''do this'           //breaking into 3 parts

The first approach seems better in that it acquires less pre modification (put the dollar symbol in front and substitute every \ to \\), but I don't know what else the DOLLAR SIGN might do.

I've really googled this but I can't find what I need...

Osteoma answered 15/8, 2012 at 8:40 Comment(2)
To better understand the $'...' example, take a look at the first paragraph of bash info pageAmbagious
Thanks for posting this question. It's crucial for understanding how to align tab-delimited records (i.e. cat myData.tsv | column -t -s$'\t')Seemly
M
136

It causes escape sequences to be interpreted.

$ echo $'Name\tAge\nBob\t24\nMary\t36'
Name    Age
Bob     24
Mary    36

After those sequences are expanded, the result is single-quoted, as if the dollar sign had not been present.

Microcurie answered 15/8, 2012 at 8:46 Comment(6)
+1 good catch. I guess this happens because variable names are expanded?Starfish
No, this happens because it's defined behavior for $'...'.Microcurie
This is exactly what i need if this is all $'' does!Osteoma
That is all $' does. It expands the POSIX string escapes (and then some): \a = BEL (bell, "alert"), \b = BS (backspace), \cX = control+X (e.g. \cG is the same as \a), \e = ESC (escape), \f = FF (form feed), \n = LF (line feed, newline), \r = CR (carriage return), \t = HT (horizontal tab), \v = VT (vertical tab).Shanty
maybe to late to the party but then why not use double quotes for this?Derivation
@Derivation double-quotes do complete shell-expansion of dollar signs, that is "foo $(echo pwn > /tmp/pwned)" will write to the file /tmp/pwned. A high price to pay for simply replacing escapes :-) However, this is a bashism, thus not portable if you want to stay with POSIX /bin/sh. You'd need to do this manually there.Superfetation
S
46

Using $ as a prefix tells BASH to try to find a variable with that name. $' is a special syntax (fully explained here) which enables ANSI-C string processing. In this case, the single tick isn't "take value verbatim until the next single tick". It should be quite safe to use. The drawbacks are it's BASH only and quite uncommon, so many people will wonder what it means.

The better way is to use single quotes. If you need a single quote in a string, you need to replace it with '\''. This ends the previous single quoted string, adds a single quote to it (\') and then starts a new single quoted string. This syntax works with any descendant of the Bourne shell, it's pretty easy to understand and most people quickly recognize the pattern.

The alternative is to replase each single tick with '"'"' which translates to "terminate current single quoted string, append double quoted string which contains just a single tick, restart single quoted string". This avoid the escape character and looks nicely symmetric. It also works the other way around if you need a double quote in a double quoted string: "'"'".

Starfish answered 15/8, 2012 at 8:48 Comment(4)
It is also common to see '"'"'. eg 'the dog'"'"'s tail'Sauropod
$'SHELL' and $'LANG' will not "fail". The dollar sign in $' has a different function. I'd say '\'' is one correct way.Stereotropism
$'...' is targeted for inclusion in POSIX. [mywiki.wooledge.org/Bashism] [austingroupbugs.net/view.php?id=249]Citral
Was searching the term for long, until I reached the link in this answer.Prosper
R
-3

You won't find a faster or more efficient way than:

eval RESULT=\$\'$STRING\'

For one, this is the kind of thing that eval is there for, and you avoid the crazy cost of forking subprocess all over the place, as the previous answers seem to suggest. Your example:

$ foo='\u25b6'
$ eval bar=\$\'$foo\'
$ echo "$bar"
▶
Regan answered 6/1, 2015 at 10:11 Comment(1)
This is a misunderstanding of what the syntax means in Bash. $'...' is a C-style string which obeys different quoting rules than regular strings, as outlined in the other answers on this page.Belgian

© 2022 - 2024 — McMap. All rights reserved.