Search code examples
bashcat

evaluate bash variables in nested cat


I have a shell script that looks like

#/bin/bash

file=File1.sh

cat > ${file} << EOF
file2=subCat
cat > ${file2} << END
echo hello
END

EOF

Which produces File1.sh with the contents:


file2=subCat

cat> << END
echo hello
END

How can I get ${file2} to be evaluated as subCat in the output file?


Solution

  • Here's an easier way to reproduce your problem:

    echo "var=foo"
    echo $var
    

    It outputs nothing instead of foo. This is because outputting a value with an equals sign is not the same as actually assigning a value.

    What you asked can be done by assigning the variable first instead of outputting it:

    #/bin/bash
    
    file=File1.sh
    file2=subCat
    
    cat > ${file} << EOF
    cat > ${file2} << END
    echo hello
    END
    EOF
    

    This will make File1.sh contain

    cat > subCat << END
    echo hello
    END
    

    What you maybe should have asked is how to make the expansion happen in File1.sh instead. You can do this by escaping the expansion:

    #/bin/bash
    
    file=File1.sh
    
    cat > ${file} << EOF
    file2=subCat
    cat > \${file2} << END
    echo hello
    END
    EOF
    

    This will make File1.sh contain

    file2=subCat
    cat > ${file2} << END
    echo hello
    END
    

    If you want all expansions to happen in the script, you can also simply quote 'EOF' instead of each individual one.