0

I'm looking for a simple way to include multi-line scripts inline in documentation to make it transparent what each step does.

This works

echo "echo 1234" | bash

So does this

echo 'for N in 1 2 3; do echo $N; done' | bash

However, I'd like to use something like this (which does not work):

echo <<EOF | bash
for N in 1 2 3; do
echo "N is ${N}"
done
EOF

Update, the closest working solution so far is:

cat <<EOF|bash
for N in 1 2 3 4; do
    echo "N is now \$N"
done
EOF

Ideally though I'd like to not have to escape the \$N

A correct solution will not:

  • use tools not installed default debian config
  • involve a temp file
  • downloaded the script ( curl -o - htpp://blah.com/script | bash etc )

Ideally it's something something the reader can copy paste, press enter, and will execute without further action.

Nanzikambe
  • 265
  • 2
  • 8

2 Answers2

1

I think the best you can do is something like this:

bash -c '
    echo "Simple scriptlike thingy"
    for I in 1 2 3 45; do
      echo "I is now ${I}"
    done
'

Note that this essentially gives the while script as a parameter to the -c switch, and this parameter itself will be parsed by bash. This is why you can't use " signs like this:

bash -c "
    THING=text
    echo this will not work: $THING
"

because in the parameter, $THING is substituted before passed as argument, and since THING is unset, it will be replaced to an empty string. A string enclosed in apostrophes is not parsed, so it can be used to contain variables to be set when the "second bash process" parses the script.

For more complex scripts, I think the best way would be to ask your readers to save the script and run it, but for simple constructs, the above should work.

Lacek
  • 6,585
  • 22
  • 28
  • thanks for the answer, `bash -c 'blah'` will work for 90% of my needs, I'm going to hold out for a while for an answer which allows both " and ' -- just in case – Nanzikambe Mar 07 '20 at 13:25
1

If you quote or escape the here-document delimiter (i.e. <<'EOF' or <<\EOFinstead of just <<EOF), the shell won't do expansions (of variables etc) on the content.

cat <<'EOF' | bash
for N in 1 2 3; do
echo "N is ${N}"
done
EOF

BTW, the cat command isn't really doing anything useful here (it's what's known as a "useless use of cat", or UUoC). You can eliminate it and send input directly to bash:

bash <<'EOF'
for N in 1 2 3; do
echo "N is ${N}"
done
EOF

If the snippet needs to read input, that's a little tricky because the script's input is... the script snippet itself. On most unix-like OSes, you can avoid this by passing the script over a different file descriptor, and telling bash to "execute" that file descriptor:

bash /dev/fd/3 3<<'EOF'
read -p "Enter something here: " input
echo "You entered: ${input}"
EOF

But note that any variables set in one of these snippets (like $input here) are only set in that one shell process, and will be lost when it exits.

Gordon Davisson
  • 11,036
  • 3
  • 27
  • 33