Prevent expansion of \c in echo argument

Viewed 125

I'm building a shell script with echo. I have something like:

echo "sed -i \"\\|charlie\.url\\s*=\\s*.*|c\\charlie.url = ${CHARLIE_URL}\" foo.conf" >> bar.sh

i.e. replace the line in foo.conf containing the current charlie.url (not necesarily at the begining, 'cause the line could be commented) for a new line with a new url.

I would expect the output to bar.sh to be

sed -i "\|charlie\.url\s*=\s*.*|c\charlie.url = ${CHARLIE_URL}" foo.conf

Nevertheless, the c\\charlie is interpreted as c \c harlie, instead of c\ charlie, which generates the following output:

sed -i "\|charlie\.url\s*=\s*.*|c

I have found that I could prevent this by using single instead of doubles quotes, but in that case ${CHARLIE_URL} (which I do need to expand) does not get expanded.

How should my echo argument look like?

I'm using dash (#!/bin/sh under Ubuntu), but I could also use bash or zsh.

3 Answers

Instead of echo, you can try cat :

cat << EOF >> bar.sh
sed -i "\|charlie\.url\s*=\s*.*|c\charlie.url = ${CHARLIE_URL}" foo.conf
EOF
#!/bin/bash

# bash will expand content within "" and stuff like $URL gets expanded
# also double-backslash reduces to a single; bash wouldn't expand stuff within ''

URL="https..."
echo double: "c\\charlie.url, URL $URL"
echo single: 'c\\charlie.url, URL $URL'

# if you need to output a \\
echo "\\\\"

The command line is using your first slash to quote your second one. If CHARLIE_URL=foo, your echo is actually outputting

sed -i "\|charlie\.url\s*=\s*.*|c\charlie.url = foo" foo.conf

Try using single quotes, but close/open them around the variable.

echo 'sed -i "\\|charlie\.url\\s*=\\s*.*|c\\charlie.url = '"${CHARLIE_URL}"'" foo.conf'

This produces

sed -i "\\|charlie\.url\\s*=\\s*.*|c\\charlie.url = foo" foo.conf

You could also, as mentioned, quote the slash that quotes the slash, and then quote the slash being quoted by the other slash, so that the subsequent iterations boil them down to what you want... but that's generally a mess, and leads to leaning-toothpick syndrome.

Someone made a good here-doc suggestion already, so I won't repeat that, but you can also use a "here string" which I generally prefer.

cat <<< "sed -i '\|charlie\.url\s*=\s*.*|c\charlie.url = ${CHARLIE_URL}' foo.conf"

I switched the double-quotes in your script for singles, assuming what you want is to output the literal value of $CHARLIE_URL into your script. If you want the script to use the variable, with whatever value is assigned at runtime, then quote that too -

cat <<< "sed -i '\|charlie\.url\s*=\s*.*|c\charlie.url = \${CHARLIE_URL}' foo.conf"
Related