Почему в середине аргументов есть EOF?

Почему в середине аргументов есть EOF?

Я хотел написать небольшую функцию bash, которую я мог бы использовать для вызова bash import osили , from sys import stdoutи она бы создала новый интерпретатор Python с импортированным модулем.

Последняя fromфункция выглядит так:

from () {
    echo "from $@" | xxd
    python3 -i -c "from $@"
}

Если я назову это:

$ from sys import stdout
00000000: 6672 6f6d 2073 7973 2069 6d70 6f72 7420  from sys import 
00000010: 7374 646f 7574 0a                        stdout.
  File "<string>", line 1
    from sys
           ^
SyntaxError: invalid syntax
>>> 

Байты from sysв

66 72 6f 6d 20 73 79 73 20
f  r  o  m     s  y  s    

Там нет EOF, но интерпретатор Python ведет себя так, как будто он прочитал EOF. В конце потока есть новая строка, чего и следовало ожидать.

fromРодственная функция, импортирующая целый модуль Python, выглядит так и решает проблему, очищая и обрабатывая строку, а также завершая работу с ошибкой на несуществующих модулях.

import () {
  ARGS=$@
  ARGS=$(python3 -c "import re;print(', '.join(re.findall(r'([\w]+)[\s|,]*', '$ARGS')))")
  echo -ne '\0x04' | python3 -i
  python3 -c "import $ARGS" &> /dev/null
  if [ $? != 0 ]; then
    echo "sorry, junk module in list"
  else
    echo "imported $ARGS"
    python3 -i -c "import $ARGS"
  fi
}

Это решает проблему необъяснимого EOF в потоке, но мне хотелось бы понять, почему Python считает, что есть EOF.

решение1

Таблица вэтот ответ Stack Overflow(который получил его отBash Хакеры Wiki) объясняет, как расширяются различные переменные Bash:

Вы делаете python -i -c "from $@", который превращается в python -i -c "from sys" "import" "stdout", и -cпринимает только один аргумент, поэтому он запускает команду from sys. Вы хотите использовать $*, который будет расширяться в python -i -c "from sys import stdout"(предполагая, $IFSчто не установлен или начинается с пробела).

решение2

strace, как всегда, покажет, что происходит:

bash-4.1$ echo $$
3458

И в другом месте (или вы могли бы выяснить, как strace bash ...вызвать функцию):

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

И снова в той первой оболочке:

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

А затем снова в straceракушке:

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

Таким образом, фактический -cаргумент заключается -c "from sys"в том, как "$@"расширена или усечена команда, которая pythonблеет дальше.

решение3

$@в двойных кавычках расширяется до списка элементов "$1" "$2" "$3"и т.д.

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

expand sys import stdout

Python ожидает, что код будет содержать один аргумент, а не серию аргументов.

решение4

Strace показывает, какие аргументы используются. Но самый простой способ увидеть, что обрабатывается, — это добавить printf '<%s> 'перед каждой соответствующей строкой и закрытие echo(чтобы сгенерировать новую строку):

Итак, функцию можно изменить следующим образом:

from () {
    printf '<%s> ' "from $@"; echo
    printf '<%s> ' python3 -i -c "from $@"; echo
}

И когда его зовут:

$ from sys import stdout
<from sys> <import> <stdout> 
<python3> <-i> <-c> <from sys> <import> <stdout>

Ясно, что "from sys" отправляется в python как один аргумент.
Это то, что python получает, и python действует на "from sys".

Связанный контент