[bash] Expansion of variables inside single quotes in a command in Bash

I want to run a command from a bash script which has single quotes and some other commands inside the single quotes and a variable.

e.g. repo forall -c '....$variable'

In this format, $ is escaped and the variable is not expanded.

I tried the following variations but they were rejected:

repo forall -c '...."$variable" '

repo forall -c " '....$variable' "

" repo forall -c '....$variable' "

repo forall -c "'" ....$variable "'"

If I substitute the value in place of the variable the command is executed just fine.

Please tell me where am I going wrong.

This question is related to bash shell variables quotes

The answer is


Variables can contain single quotes.

myvar=\'....$variable\'

repo forall -c $myvar

Below is what worked for me -

QUOTE="'"
hive -e "alter table TBL_NAME set location $QUOTE$TBL_HDFS_DIR_PATH$QUOTE"

Does this work for you?

eval repo forall -c '....$variable'

just use printf

instead of

repo forall -c '....$variable'

use printf to replace the variable token with the expanded variable.

For example:

template='.... %s'

repo forall -c $(printf "${template}" "${variable}")

The repo command can't care what kind of quotes it gets. If you need parameter expansion, use double quotes. If that means you wind up having to backslash a lot of stuff, use single quotes for most of it, and then break out of them and go into doubles for the part where you need the expansion to happen.

repo forall -c 'literal stuff goes here; '"stuff with $parameters here"' more literal stuff'

Explanation follows, if you're interested.

When you run a command from the shell, what that command receives as arguments is an array of null-terminated strings. Those strings may contain absolutely any non-null character.

But when the shell is building that array of strings from a command line, it interprets some characters specially; this is designed to make commands easier (indeed, possible) to type. For instance, spaces normally indicate the boundary between strings in the array; for that reason, the individual arguments are sometimes called "words". But an argument may nonetheless have spaces in it; you just need some way to tell the shell that's what you want.

You can use a backslash in front of any character (including space, or another backslash) to tell the shell to treat that character literally. But while you can do something like this:

echo \”That\'ll\ be\ \$4.96,\ please,\"\ said\ the\ cashier

...it can get tiresome. So the shell offers an alternative: quotation marks. These come in two main varieties.

Double-quotation marks are called "grouping quotes". They prevent wildcards and aliases from being expanded, but mostly they're for including spaces in a word. Other things like parameter and command expansion (the sorts of thing signaled by a $) still happen. And of course if you want a literal double-quote inside double-quotes, you have to backslash it:

echo "\"That'll be \$4.96, please,\" said the cashier"

Single-quotation marks are more draconian. Everything between them is taken completely literally, including backslashes. There is absolutely no way to get a literal single quote inside single quotes.

Fortunately, quotation marks in the shell are not word delimiters; by themselves, they don't terminate a word. You can go in and out of quotes, including between different types of quotes, within the same word to get the desired result:

echo '"That'\''ll be $4.96, please," said the cashier'

So that's easier - a lot fewer backslashes, although the close-single-quote, backslashed-literal-single-quote, open-single-quote sequence takes some getting used to.

Modern shells have added another quoting style not specified by the POSIX standard, in which the leading single quotation mark is prefixed with a dollar sign. Strings so quoted follow similar conventions to string literals in the ANSI standard version of the C programming language, and are therefore sometimes called "ANSI strings" and the $'...' pair "ANSI quotes". Within such strings, the above advice about backslashes being taken literally no longer applies. Instead, they become special again - not only can you include a literal single quotation mark or backslash by prepending a backslash to it, but the shell also expands the ANSI C character escapes (like \n for a newline, \t for tab, and \xHH for the character with hexadecimal code HH). Otherwise, however, they behave as single-quoted strings: no parameter or command substitution takes place:

echo $'"That\'ll be $4.96, please," said the cashier'

The important thing to note is that the single string received as the argument to the echo command is exactly the same in all of these examples. After the shell is done parsing a command line, there is no way for the command being run to tell what was quoted how. Even if it wanted to.


EDIT: (As per the comments in question:)

I've been looking into this since then. I was lucky enough that I had repo laying around. Still it's not clear to me whether you need to enclose your commands between single quotes by force. I looked into the repo syntax and I don't think you need to. You could used double quotes around your command, and then use whatever single and double quotes you need inside provided you escape double ones.


Examples related to bash

Comparing a variable with a string python not working when redirecting from bash script Zipping a file in bash fails How do I prevent Conda from activating the base environment by default? Get first line of a shell command's output Fixing a systemd service 203/EXEC failure (no such file or directory) /bin/sh: apt-get: not found VSCode Change Default Terminal Run bash command on jenkins pipeline How to check if the docker engine and a docker container are running? How to switch Python versions in Terminal?

Examples related to shell

Comparing a variable with a string python not working when redirecting from bash script Get first line of a shell command's output How to run shell script file using nodejs? Run bash command on jenkins pipeline Way to create multiline comments in Bash? How to do multiline shell script in Ansible How to check if a file exists in a shell script How to check if an environment variable exists and get its value? Curl to return http status code along with the response docker entrypoint running bash script gets "permission denied"

Examples related to variables

When to create variables (memory management) How to print a Groovy variable in Jenkins? What does ${} (dollar sign and curly braces) mean in a string in Javascript? How to access global variables How to initialize a variable of date type in java? How to define a variable in a Dockerfile? Why does foo = filter(...) return a <filter object>, not a list? How can I pass variable to ansible playbook in the command line? How do I use this JavaScript variable in HTML? Static vs class functions/variables in Swift classes?

Examples related to quotes

YAML: Do I need quotes for strings in YAML? Regex to split a CSV Expansion of variables inside single quotes in a command in Bash How to call execl() in C with the proper arguments? Insert text with single quotes in PostgreSQL When to use single quotes, double quotes, and backticks in MySQL Difference between single and double quotes in Bash Remove quotes from a character vector in R How do I remove quotes from a string? How can I escape a double quote inside double quotes?