how to display $ in bash script

104 Views Asked by At

I have a script. I can't print $ in a screen.

#!/bin/bash

SERVER_IP=""
PASSWORD=""
DOMAIN=""
CONFIG_CONTENT=$(cat << EOF

server {
    listen 80;
    listen [::]:80;

    root /home/webmas/$DOMAIN;

    index index.php index.html index.htm index.nginx-debian.html;

    server_name $DOMAIN;

    location / {
            try_files \$uri \$uri/ =404;
    }

    location ~ \.php$ {
            include snippets/fastcgi-php.conf;
            fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    }

    location ~ /\.ht {
            deny all;
    }
}

EOF
)

ssh -tt -p 300 webmas@$SERVER_IP << EOF

mkdir $DOMAIN
cd /etc/nginx/sites-available
echo -n "$PASSWORD" | sudo -S sh -c "echo '$CONFIG_CONTENT' | tee /etc/nginx/sites-  available/$DOMAIN >/dev/null"

EOF

$uri is not displayed on the screen

I don't understand why \$ don't help. Single quotes didn't help either. I've run out of ideas.

3

There are 3 best solutions below

0
tjm3772 On BEST ANSWER

Let's simplify the problem. Start with a small heredoc:

var1=a
var2=b
doc=$( cat <<EOF
$var1 \$var2
EOF
)
echo "$doc" # prints: a $var2

Okay, so far so good. The escaped variable wasn't expanded.

ssh adds a layer of complexity to the problem, so let's skip it for a moment. Instead we'll use cat to inspect how the heredoc we want to pass to ssh actually looks after expansions.

cat <<EOF
sh -c "echo '$doc'"
EOF
# prints: sh -c "echo 'a $var2'"

Oops, I see a problem. Even though $var2 is inside single quotes in the program that we want to pass to sh, that double quoted string has to be parsed first to create the program that sh receives and $var2 will be expanded at that point. If you copy sh -c "echo 'a $var2'" into a terminal and run it you'll see the output is a b.

So, now that we know the problem, what are the solutions?

You could manually add extra escaping to the original document:

doc=$( cat <<EOF
$var1 \\\$var2
EOF
)
echo "$doc" # prints: a \$var2
cat <<EOF
sh -c "echo '$doc'"
EOF
# prints: sh -c "echo 'a \$var2'"
sh -c "echo 'a \$var2'" # prints a $var2

You could pass the document as an argument to sh instead of directly injecting it into the command string which would remove a layer of interpretation:

doc=$( cat <<EOF
$var1 \$var2
EOF
)
echo "$doc" # prints: a $var2
cat <<EOF
sh -c 'echo "\$1"' _ '$doc'
EOF
# prints: sh -c 'echo "$1"' _ 'a $var2'
sh -c 'echo "$1"' _ 'a $var2' # prints: a $var2

You could also look at the "automatic requoting" feature documented in BashFAQ/096 or, as another user suggested, place the document in a file and scp it to the host instead of trying to work around the multiple levels of interpretation happening with your heredoc.

4
Gilles Quénot On

Use the quoted way on here document:

foobar<<'EOF'
$XYZ
EOF

if you need ko keep expansion for some variables:

foobar<<EOF
\$XYZ # not expanded
$XXX  # expanded
EOF
0
Artem On

So, I found the answer. Because of the cat, the script tried to substitute the value twice. The first time in cat, the second time when writing to the file itself. Therefore, I had to screen $ twice. The '\$' structure helped. That is, I used both quotation marks and a backslash at once. It worked.