How to handle shell script arguments in heredoc?

2019-09-08 19:17发布

问题:

I need to switch to oracle user to change permissions to tnsnames.ora file. I am passing this file path as argument but looks like somewhere the syntax is wrong. Appreciate help in fixing this issue.

Belows is the peice of my script.

#!/bin/bash

sudo su - oracle <<-"EOF"
    chmod 777 "$1"
EOF

It is failing by giving the following error:

/home/itsh->./dothis.sh /home/oracle/orasys/11.2.0.2/network/admin/tnsnames.ora
chmod: cannot access `': No such file or directory

回答1:

The operation of a here document is specified in the POSIX spec where it says:

If any character in word is quoted, the delimiter shall be formed by performing quote removal on word, and the here-document lines shall not be expanded. Otherwise, the delimiter shall be the word itself.

If no characters in word are quoted, all lines of the here-document shall be expanded for parameter expansion, command substitution, and arithmetic expansion. In this case, the in the input behaves as the inside double-quotes (see Double-Quotes). However, the double-quote character ( '"' ) shall not be treated specially within a here-document, except when the double-quote appears within "$()", "``", or "${}".

So by using <<-"EOF" (instead of <<-EOF) as your here document marker you are explicitly telling the shell not to expand any variables (from the shell context) in the here document contents.

This is often what you want when you are using a heredoc for a shell snippet but in your case this is exactly the opposite of what you appear to be looking for.



回答2:

If you're in any way concerned about security, the right thing to do is not to change your quoting, but to keep it as it is and use bash -s to pass your arguments to the shell running as the oracle user directly:

#!/bin/bash
sudo -u oracle bash -s "$@" <<-'EOF'
    chmod 777 "$1"
EOF

...or, if you must use sudo su - oracle (which I'd argue is bad practice, and best avoided):

#!/bin/bash
printf -v sudo_cmd '%q ' bash -s "$@"
sudo su - oracle -c "$sudo_cmd" <<-'EOF'
    chmod 777 "$1"
EOF

With either of these practices, your inner shell runs the $1 expansion itself -- and the data on the command line isn't substituted into, and parsed as, code.



标签: shell