Bash: Echoing a echo command with a variable in bash

160,276

Solution 1

The immediate problem is you have is with quoting: by using double quotes ("..."), your variable references are instantly expanded, which is probably not what you want.

Use single quotes instead - strings inside single quotes are not expanded or interpreted in any way by the shell.

(If you want selective expansion inside a string - i.e., expand some variable references, but not others - do use double quotes, but prefix the $ of references you do not want expanded with \; e.g., \$var).

However, you're better off using a single here-doc[ument], which allows you to create multi-line stdin input on the spot, bracketed by two instances of a self-chosen delimiter, the opening one prefixed by <<, and the closing one on a line by itself - starting at the very first column; search for Here Documents in man bash or at http://www.gnu.org/software/bash/manual/html_node/Redirections.html.

If you quote the here-doc delimiter (EOF in the code below), variable references are also not expanded. As @chepner points out, you're free to choose the method of quoting in this case: enclose the delimiter in single quotes or double quotes, or even simply arbitrarily escape one character in the delimiter with \:

echo "creating new script file."

cat <<'EOF'  > "$servfile"
#!/bin/bash
read -p "Please enter a service: " ser
servicetest=`getsebool -a | grep ${ser}` 
if [ $servicetest > /dev/null ]; then 
  echo "we are now going to work with ${ser}"
else
  exit 1
fi
EOF

As @BruceK notes, you can prefix your here-doc delimiter with - (applied to this example: <<-"EOF") in order to have leading tabs stripped, allowing for indentation that makes the actual content of the here-doc easier to discern. Note, however, that this only works with actual tab characters, not leading spaces.

Employing this technique combined with the afterthoughts regarding the script's content below, we get (again, note that actual tab chars. must be used to lead each here-doc content line for them to get stripped):

cat <<-'EOF' > "$servfile"
    #!/bin/bash
    read -p "Please enter a service name: " ser
    if [[ -n $(getsebool -a | grep "${ser}") ]]; then 
      echo "We are now going to work with ${ser}."
    else
      exit 1
    fi
EOF

Finally, note that in bash even normal single- or double-quoted strings can span multiple lines, but you won't get the benefits of tab-stripping or line-block scoping, as everything inside the quotes becomes part of the string.

Thus, note how in the following #!/bin/bash has to follow the opening ' immediately in order to become the first line of output:

echo '#!/bin/bash
read -p "Please enter a service: " ser
servicetest=$(getsebool -a | grep "${ser}")
if [[ -n $servicetest ]]; then 
  echo "we are now going to work with ${ser}"
else
  exit 1
fi' > "$servfile"

Afterthoughts regarding the contents of your script:

  • The syntax $(...) is preferred over `...` for command substitution nowadays.
  • You should double-quote ${ser} in the grep command, as the command will likely break if the value contains embedded spaces (alternatively, make sure that the valued read contains no spaces or other shell metacharacters).
  • Use [[ -n $servicetest ]] to test whether $servicetest is empty (or perform the command substitution directly inside the conditional) - [[ ... ]] - the preferred form in bash - protects you from breaking the conditional if the $servicetest happens to have embedded spaces; there's NEVER a need to suppress stdout output inside a conditional (whether [ ... ] or [[ ... ]], as no stdout output is passed through; thus, the > /dev/null is redundant (that said, with a command substitution inside a conditional, stderr output IS passed through).

Solution 2

You just need to use single quotes:

$ echo "$TEST"
test
$ echo '$TEST'
$TEST

Inside single quotes special characters are not special any more, they are just normal characters.

Solution 3

echo "echo "we are now going to work with ${ser}" " >> $servfile

Escape all " within quotes with \. Do this with variables like \$servicetest too:

echo "echo \"we are now going to work with \${ser}\" " >> $servfile    
echo "read -p \"Please enter a service: \" ser " >> $servfile
echo "if [ \$servicetest > /dev/null ];then " >> $servfile
Share:
160,276
David
Author by

David

By Day: I'm a computer guy. By Night: I'm a computer guy with a family. For Fun: I chase my kids. Nothing special here, move along.

Updated on July 09, 2022

Comments

  • David
    David almost 2 years

    Ok, here is one I am struggling with as we speak. Echoing a echo command with a variable.

    echo "creating new script file."
    echo "#!/bin/bash" > $servsfile
    echo "read -p "Please enter a service: " ser " >> $servfile
    echo "servicetest=`getsebool -a | grep ${ser}` " >> $servfile
    echo "if [ $servicetest > /dev/null ];then " >> $servfile
    echo "echo "we are now going to work with ${ser}" " >> $servfile
    echo "else" >> $servfile
    echo "exit 1" >> $servfile
    echo "fi" >> $servfile
    

    My goal is create a script using echo commands then run it later. I just need to figure out how to echo echo/read commands while maintaining my variables.

    edit: the variables need to transfer what's inside of them into the new file.

  • Bruce K
    Bruce K about 10 years
    That first line looks kind-of dodgey. If you want them in the result script, you need to quote them. Or just use a "heredoc", as I suggested.
  • GoinOff
    GoinOff about 10 years
    Got it. heredoc is a way better solution to this problem. Just learned about it from this post and will use it going forward..Thx!!
  • palme
    palme about 5 years
    But you definitely have to deal with sad characters after that :D
  • HarshaD
    HarshaD almost 3 years
    cat <<'EOF' >> "$servfile" . . EOF I had to do this in order for it to work!