Passing a variable to a bash script that uses 'EOF' and considers the variable a literal

52,139

Solution 1

Following up on your previous question, it sounds like you want both some uninterpreted text and some interpreted text going into a file. In that case, use two different cats (or echos):

cat > /test <<'EOF'
some uninterpreted text $(pwd)
not substituted: $1
EOF
cat >> /test <<EOF
but this will substitute: $1
EOF

There's a couple of things going on here: firstly, the heredoc syntax with <<. If you include quotes in that terminator string, as in the first one above, the entire heredoc is uninterpreted — no parameters and no substitutions. If you don't use any quotes, like in the second cat above, variables like $1 will be replaced by their values and command substitutions will be included in the text. You choose between whether to quote the "EOF" string or not based on whether you want substitutions or not.

To put both cats into the same file we're using >> redirection for the second (and any later) redirections: that means to append to the file. For the first one, we use a single > to clear the file out and start fresh.

Note that, even when variables are substituted, any additional dollar signs in that variable's value aren't re-substituted themselves:

foo='$bar'
bar=hello
cat <<EOF
$foo
EOF

will output:

$bar

without substituting in $bar's value.

However, if you're providing a "$" in the argument to this whole script, you need to escape it on the command line or enclose the whole thing in single quotes. Alternatively, command substitution as in your other question lets you put the contents of a whole file in directly, including any dollar signs in the file contents. Make sure you quote the substitution string there:

oo.sh "$(cat myfile)"

will get the body of myfile as $1 and can then cat or echo it as required. The same limitations as in my answer there apply: there's a limit for how long the command-line arguments can be, and if your file might get longer than that you should find another approach. You can find out what the limit is on your system with getconf ARG_MAX

Solution 2

Sounds like you simply want to output the one variable to the file. In that case, this will work:

echo $1 >/test

Note that /test is in the root directory, which ordinary users don't usually have write permission for.

EDIT: Bear in mind that you need to quote the dollar-sign-containing string in the command line. That is where the substitution occurs, and the script can't do anything about it after the fact.

Share:
52,139

Related videos on Youtube

user72685
Author by

user72685

Updated on September 18, 2022

Comments

  • user72685
    user72685 over 1 year

    in this script i end up with "$1" being saved to the /test file.

    #!/bin/bash
    cat > /test << 'EOF'
    $1
    EOF
    

    the truth is.. i need to keep

    'EOF'
    

    as 'EOF' because my argument($1) contains dollar signs.

    but i need that argument to be saved rather than $1

    • goldilocks
      goldilocks almost 10 years
      'because my argument($1) contains dollar signs.' Not if it refers to the first command line parameter. Substitution was performed on that before your script executed. You have to escape it on the command line.
    • Gilles 'SO- stop being evil'
      Gilles 'SO- stop being evil' almost 10 years
      You've asked several related questions about this task you're doing, and the progression of questions shows that you don't really understand what's going on and are probably not choosing the easiest approach. It's difficult to help you without knowing what you're trying to do, so I recommend that you ask a question where you clearly explain your overall task and don't constrain the answers to use a particular tool. For example, don't say “I want to use cat and keep dollar signs”, but “I want to modify the httpd.conf to change <some setting> in <this manner>”.
    • user72685
      user72685 almost 10 years
      @Gilles, the reason why my questions do not make sense is because the way bash scripts handle variables passed on to them. there are too many things that have to be escaped and yet there is not a feature to encode and decode on the fly.
    • user72685
      user72685 almost 10 years
      @Gilles, the only thing that made sense to me a bit was base64 but why must one have to encode their stuff in order to pass to a bash script.. escaping things and then trying to re-construct things within the bash script.. the whole three forward slashes to escape a backtick and etc.. it seems to me like a code hell
    • Gilles 'SO- stop being evil'
      Gilles 'SO- stop being evil' almost 10 years
      @user72685 It's rare to need to do any encoding. Usually, if you're getting garbled output, it's because you didn't quote things properly, and the solution is to add the missing quotes, not to try to make the hamburger back into a cow. In particular, always use double quotes around variable substitutions, i.e. "$foo" and not $foo.
    • user72685
      user72685 almost 10 years
      @Gilles, this is not about those double quotes within the bash script. this is the whole process of passing a variable to a bash script externally. you can not pass a variable that contains quotes, single quotes, dollar signs, back ticks and i think one other element. but it even gets crazier.. if you are passing it in double quotes.. you only can escape the single quotes.. if you are passing it in single quotes.. you can only escape the double quotes.. all this work just to pass a string to the bash script.. and then within the script.. a whole nother story..
    • Gilles 'SO- stop being evil'
      Gilles 'SO- stop being evil' almost 10 years
      @user72685 No, you can pass a variable containing anything except a null byte. Evidently you're having some problem somewhere in the part of your work that you didn't show, and you're trying to solve it in the wrong place.
    • user72685
      user72685 almost 10 years
      @Gilles, even if i fixed the string.. which happened to be httpd.conf file itself. the answers on the internet were not addressing on how to echo this to a file.. i saw too many crazy things.. such as 3 forward slashes.. 1 to escape the back tick one to escape the forward slash.. and then one to escape the forward slash that was escaping the other forward slash which was escaping the back tick.. this kind of stuff is simply an indication for me to not go any further and stick to something else.. such as write to a file and then copy the file to the original path via cat or something else.
    • derobert
      derobert almost 10 years
      You save the contents of $1 to a file like this: echo "$1" > file. That works. Your problem, as Gilles has been trying to tell you, is elsewhere.
  • goldilocks
    goldilocks almost 10 years
    I think you have the correct answer now. +1
  • Tom Zych
    Tom Zych almost 10 years
    @MichaelHomer's answer is much more complete and includes useful information about here documents that I'd forgotten. His answer should be accepted (unless someone else posts an even better one, of course).