Чому в середині аргументів є EOF?


20

Я хотів написати невелику функцію 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.

Відповіді:


42

Таблиця у цій відповіді на переповнення стека (яка отримана від Віки Bash Hackers ) пояснює, як розширюються різні змінні Bash:

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


2
Дякую за те, що визнали, що це цінна інформація :)
кіт

1
Я думаю, що це має бути прийнятою відповіддю, оскільки це фактично вирішує проблему, інший, який схвалює, просто пояснює проблему, але не дає рішення та альтернативних шляхів вирішення
Феррібіг,

Гарна відповідь. Ця таблиця насправді походить з Вікі Bash Hackers. Чи можете ви додати належну атрибуцію та підтвердити, що маєте право на розповсюдження?
Гонки легкості з Монікою

22

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перетворюється.


9

$@у подвійних лапках розширюється до списку елементів "$1" "$2" "$3"тощо.

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

expand sys import stdout

Python очікує, що код буде в одному аргументі, а не в ряді аргументів.


6

Python викликається як

execve("/usr/bin/python", ["python", "-i", "-c", "from sys", "import", "stdout"], [/* 54 vars */])

(див . відповідь трига ).

Щоб отримати $@розширення як єдиний рядок (якщо вважати здоровим $IFS), ви можете використовувати $*внутрішні подвійні лапки:

python3 -i -c "from $*"

Підтверджено strace -e execve:

execve("/usr/bin/python", ["python", "-i", "-c", "from sys import stdout"], [/* 54 vars */]) = 0

2

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 як один аргумент.
Ось що отримує пітон, а пітон діє на "від sys".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.