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.
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.