Why is there an EOF in the middle of the arguments?

The table in this Stack Overflow answer (which got it from the Bash Hackers Wiki) explains how the different Bash variables are expanded:

You're doing python -i -c "from $@", which turns into python -i -c "from sys" "import" "stdout", and -c only takes a single argument, so it's running the command from sys. You want to use $*, which will expand into python -i -c "from sys import stdout" (assuming $IFS is unset or starts with a space).


strace, as always, will show what is going on:

bash-4.1$ echo $$
3458

And, elsewhere (or you could figure out how to strace bash ... the function call):

bash-4.1$ strace -ff -o blah -p 3458

And back in that first shell:

bash-4.1$ from sys import stdout
  File "<string>", line 1
    from sys
           ^
SyntaxError: invalid syntax
>>> 
bash-4.1$ 

And then back in the strace shell:

Process 3458 attached
Process 25224 attached
^CProcess 3458 detached
bash-4.1$ grep exec blah.*
blah.25224:execve("/usr/bin/python", ["python", "-i", "-c", "from sys", "import", "stdout"], [/* 54 vars */]) = 0

Thus, the actual -c argument is -c "from sys" because of how "$@" is expanded, or a truncated command that python barfs on.


$@ in double quotes expands to a list of elements "$1" "$2" "$3" etc.

#!/bin/bash
expand () {
    for string in "from $@" ; do
        echo "$string"
    done
}

expand sys import stdout

Python expects the code to be in one argument, not a series of arguments.

Tags:

Python

Bash