34

In bash I can create a script with a here-doc like so as per this site: http://tldp.org/LDP/abs/html/abs-guide.html#GENERATESCRIPT

(
cat <<'EOF'
#!/bin/bash
#? [ ] / \ = + < > : ; " , * | 
#/ ? < > \ : * | ”
#Filename="z:"${$winFn//\//\\}
echo "This is a generated shell script."
App='eval wine "C:\Program Files\foxit\Foxit Reader.exe" "'$winFn'"'
$App
EOF
) > $OUTFILE

If my $OUTFILE is a directory requiring sudo privileges where do I put the sudo command or what else can I do to make it work?

D W
  • 2,979
  • 4
  • 34
  • 45
  • I suppose one solution is to generate the file to a temporary location and then move it with sudo to the proper location. Is that the most elegant way to do it? – D W Dec 10 '10 at 18:31

4 Answers4

76

This is how I would do it:

sudo tee "$OUTFILE" > /dev/null <<'EOF'
foo
bar
EOF
Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
29

Just putting sudo before cat doesn't work because >$OUTFILE attempts to open $OUTFILE in the current shell process, which is not running as root. You need the opening of that file to happen in a sudo-ed subprocess.

Here's one way to accomplish this:

sudo bash -c "cat >$OUTFILE" <<'EOF'
#!/bin/bash
#? [ ] / \ = + < > : ; " , * | 
#/ ? < > \ : * | ”
#Filename="z:"${$winFn//\//\\}
echo "This is a generated shell script."
App='eval wine "C:\Program Files\foxit\Foxit Reader.exe" "'$winFn'"'
$App
EOF

This starts a sub-shell under sudo, and opens $OUTFILE from that more privileged subprocess, and runs cat (as yet another privileged subprocess). Meanwhile, the (less privileged) parent process pipes the here-document to the sudo subprocess.

Laurence Gonsalves
  • 137,896
  • 35
  • 246
  • 299
  • This works for my minimum working example but not for my actual script. I have made my minimum working example sufficiently more complicated, can you help me with the new script? – D W Dec 10 '10 at 18:44
  • @D W: I'd unquoted your here-word, which may have been the source of your trouble. Sorry about that. Try re-quoting it, as shown in my updated answer. – Laurence Gonsalves Dec 10 '10 at 18:58
  • @D W: have you tried the updated answer? It works with the newer code in your question. I just went and updated it again to actually include the code from your question. – Laurence Gonsalves Dec 10 '10 at 19:06
  • interesting that the quotes make that much difference. Perfect, thanks. – D W Dec 10 '10 at 19:08
  • 2
    @D W: Yeah, I was surprised by this myself. From http://www.gnu.org/software/bash/manual/bashref.html#Redirections : "If word is unquoted, all lines of the here-document are subjected to parameter expansion, command substitution, and arithmetic expansion." Useful maybe, but what a horrible syntax! My long-running theory is that most of bash syntax was designed around what was a syntax error in previous versions (with sh being the ancestral root). – Laurence Gonsalves Dec 10 '10 at 19:31
  • @LaurenceGonsalves "most of bash syntax was designed around what was a syntax error in previous versions". Hilarious and reasonable at the same time! Glorious! – louisgab Apr 21 '18 at 14:00
  • PERFECT! (you don't need to quote the 'EOF' btw) – Amir Mehler May 04 '18 at 12:30
  • @AmirMehler Thanks. The "here word", EOF, does need to be quoted in this case. See my comment from Dec 10, '10 for details. – Laurence Gonsalves May 04 '18 at 21:08
1

You can also use dd for that:

sudo dd of="$OUTFILE" <<EOF
foo
bar
EOF
j-hap
  • 150
  • 1
  • 2
  • 9
0

Non of the answers expanded environment variables. My workaround is a tmp file and a sudo mv.

l_log=/var/log/server/server.log
l_logrotateconf=/etc/logrotate.d/server
tmp=/tmp/$$.eof
cat << EOF > $tmp
$l_log {
   rotate 12
   monthly
   compress
   missingok
   notifempty
}
EOF
sudo mv $tmp $logrotateconf
Wolfgang Fahl
  • 15,016
  • 11
  • 93
  • 186