0

This typical Bash scripting idiom for assigning a multi-line string literal to a varibale:

read -r -d '' FILE_CONTENTS <<'EOF'
... contents ...
EOF

has been serving me just fine everywhere I used it.

I run a script containing this idiom as root today, and all hell broke lose. Files would become corrupt, all sorts of weird stuff falling from the sky. I vaporised my Mac. BTW, this mistake has destroyed... everything basically. If I could upvote myself for being nuclear, I would. Effectiveness in self-destruction.


Nuclear
(source: iliketowastemytime.com)


Let me provide you with a minimal working config to reproduct it:

# Recreating a .vimrc file, for example
read -r -d '' FILE_CONTENTS <<'EOF'
    let mapleader = "<space>"
    let maplocalleader = "\\"
EOF
echo "${FILE_CONTENTS}" > .vimrc

This works just fine as user tinosino but... as root... anything with a backslash is problematic.

Why? Where to look for "the difference"? Options? Environment? Aliases on "echo" (?!) I am lost. Tried bash -x too: pages and pages of failure on the script I am testing. What could have changed what, in the setup for root? Where?

OS X version: 10.8.2
Bash version: 3.2.48(1)-release

I have a sh Vs bash guard in the script but that did not work... was it badly constructed?

if [ ${BASH_VERSION-not_running_within_bash} = not_running_within_bash ]; then
  echo This script is meant to be executed by the Bash shell but it isn\'t.
  echo Continuing from another shell may lead to unpredictable results.
  echo Execution will be aborted... now.
  return
fi

It stops zsh but doesn't stop sh from running the script... how could I do that?

EDIT: I resorted to change the script guard to this:

if [[ ! $(ps -p $$ -o comm | paste -s - | awk '{ print $NF }') == *bash* ]]; then
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Robottinosino
  • 10,384
  • 17
  • 59
  • 97
  • 3
    #!/bin/bash != #!/bin/sh . Good luck. – shellter Oct 09 '12 at 18:34
  • And that's a twisted way to write that file. Why do you use a variable at all? – Mat Oct 09 '12 at 18:37
  • @Mat: nah, I don't think that's twisted at all, actually. How else would you pass the contents of a file to be written to a function which should filter and dump the contents, without writing the contents to disk? (why not? race condition, they may be read in transit and that should not happen). Recommend an improvement if you know of one, please. – Robottinosino Oct 09 '12 at 18:40
  • Calm down. You are not giving much to go on "*anything with a backslash is problematic*" what is the problem? "*pages and pages of failure on the script I am testing*" please show the first few error lines. First off, you are playing with vi(1), have you screwed-up the .virc such that it is producing incorrect script files? – cdarke Oct 09 '12 at 18:43
  • @cdarke: look, the problem is that I let it run with sh rather than bash, which - if you test it - is refractory to the idiom I describe! – Robottinosino Oct 09 '12 at 18:48
  • @Robottinosino: ok, but still twisted. I don't understand why you don't just use a plain multiline string. – Mat Oct 09 '12 at 19:01
  • @Mat: You may be right and I may be wrong. Please provide a code example in an answer for me to review? – Robottinosino Oct 09 '12 at 19:04
  • @shellter: add your input as an answer and I'll accept it? – Robottinosino Oct 09 '12 at 19:08
  • http://stackoverflow.com/questions/3199893/howto-detect-bash-from-shell-script – initall Oct 09 '12 at 19:09

2 Answers2

2

Don't forget that the root usually runs scripts as #!/bin/sh

The errors you describe sound like scripts written for #!/bin/bash being run with #!/bin/sh. On some systems #!/bin/sh points to #!/bin/bash, so your bash-ismed code will work, but when run with a true Bourne Shell (#!/bin/sh), the bashisms will cause the script to fail, and sometimes, as in your case, in very catastrophic ways.

Just noticing your test for BASH_VERSION. Good idea. I'm betting that it doesn't do what you expect because of the =. try -eq instead. I don't have a true Bourne Shell to test with.

Sorry and good luck.

shellter
  • 36,525
  • 7
  • 83
  • 90
0

This would be another way to do it:

#!/bin/bash
(
cat <<'EOF'
let mapleader = "<space>"
let maplocalleader = "\\"
EOF
) > .vimrc
initall
  • 2,385
  • 19
  • 27
  • 1
    Thanks but could you amend your input with a case in which FILE_CONTENTS is passed to a Bash function in a better way than I do, which is what I need? – Robottinosino Oct 09 '12 at 19:29