Charlie
Charlie

Reputation: 3094

Unexpected behaviour running remote script

I'm attempting to write a script that runs on a remote machine.

As this script is complex, I've broken parts of it down into functions that I then copy into the script using typeset.

When I run the script, I get the following error:

bash: -c: line 4: syntax error: unexpected end of file

However, there is no unexpected end of file! I ensured all ifs had fis, all { had }, etc.

I've ensured all indentation uses tabs (and spaces), and ensured new-line characters are consistent.

I've stripped the code down to a minimal example. It seems as though for a function to be valid, it needs to end in a construct such as if fi or while done.

Here's what isn't working.

func() {
  ls ~/
}

ssh -A -T user@machine_ip '
'$(typeset -f func)'
func
'

Line 4 coincides with the end } of the func function (counting lines from after ssh -A -T... as this error is happening on the remote machine).

Yet, if we add a construct to the end of the function, the home directory is printed as expected.

func() {
    ls ~/
    if [[ 1 ]]; then
      echo "Hello"
    fi
}

or

func() {
    ls ~/
    while false; do
        echo "Here"
    done
}

Output of typeset -f func is

func () 
{ 
    ls --color=auto ~/;
    if [[ -n 1 ]]; then
        echo "Hello";
    fi
}

I'm running Ubuntu 18.04 LTS, remote machine is running Centos 6.

Upvotes: 0

Views: 61

Answers (2)

kapad
kapad

Reputation: 48

first of all, the way you use quotes make no sense to me.

ssh -A -T user@machine_ip '
'$(typeset -f func)'
func
'

the 2 first ' just echo an empty line. ( the 2nd ' close the 1st. logic ? )

Anyway.

$(typeset -f func)
func

the code above will execute func 2 times. At least, thats how it works for me

....

Upvotes: 0

Amadan
Amadan

Reputation: 198294

Because bash plays with whitespace if you let it. Let me explain:

$(typeset -f func) will evaluate typeset -f func and insert its output into the current command line. If not quoted, it will also segment into parameters, which will have as a side effect collapsing of all whitespace to a single space. Thus, if typeset -f func prints (as it does on my system)

func () 
{ 
    /bin/ls --color=auto ~/
}

what you get with $(typeset -f func) is

func () { /bin/ls --color=auto ~/ }

(Try echo $(typeset -f func) if you don't believe me :D )

Now, bash is really bashful about accepting smushed-up code. For example, you may know that this is not grammatical:

if true then echo "yes" fi

and this is:

if true; then echo "yes"; fi

In the same way, the function definition's closing parenthesis is picky. Thus, this works:

func () { /bin/ls --color=auto ~/; }

but this doesn't:

func () { /bin/ls --color=auto ~/ }

For some reason, bash is fine with a keyword being just before the parenthesis:

func () { /bin/ls --color=auto ~/; if [[ -n 1 ]]; then echo "Hello"; fi }
func () { /bin/ls --color=auto ~/; while false; do echo "Here"; done }

To combat this... try not sending stuff from command line, which mangles your whitespace, but from redirection:

ssh -A -T user@machine_ip < <(typeset -f func; echo func)

Or, simplest of all, prevent bash mangling of whitespace using double quotes:

ssh -A -T user@machine_ip "$(typeset -f func)
func"

Upvotes: 1

Related Questions