Por que existe um EOF no meio das discussões?

Por que existe um EOF no meio das discussões?

Eu queria escrever uma pequena função bash para que eu pudesse dizer ao bash, import osou from sys import stdoutela geraria um novo interpretador Python com o módulo importado.

A última fromfunção fica assim:

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

Se eu chamar isso:

$ 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
>>> 

Os bytes em from syssão

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

Não há EOF ali, mas o interpretador Python está se comportando como se lesse EOF. Há uma nova linha no final do fluxo, o que é esperado.

fromA irmã de, que importa um módulo Python inteiro, tem esta aparência e resolve o problema limpando e processando a string e falhando em módulos inexistentes.

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
}

Isso resolve o problema de um EOF inexplicável no fluxo, mas eu gostaria de entender por que o Python pensa que existe um EOF.

Responder1

A mesa emesta resposta do Stack Overflow(que obteve doWiki Bash Hackers) explica como as diferentes variáveis ​​Bash são expandidas:

Você está fazendo python -i -c "from $@", que se transforma em python -i -c "from sys" "import" "stdout", e -csó leva um único argumento, então está executando o comando from sys. Você deseja usar $*, que será expandido para python -i -c "from sys import stdout"(supondo que $IFSnão esteja definido ou comece com um espaço).

Responder2

strace, como sempre, mostrará o que está acontecendo:

bash-4.1$ echo $$
3458

E, em outro lugar (ou você pode descobrir como fazer strace bash ...a chamada de função):

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

E de volta àquela primeira concha:

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

E então de volta ao straceshell:

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

Assim, o argumento real -cé -c "from sys"por causa de como "$@"é expandido ou de um comando truncado que pythoncontinua vomitando.

Responder3

$@entre aspas duplas expande para uma lista de elementos "$1" "$2" "$3", etc.

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

expand sys import stdout

Python espera que o código esteja em um argumento, não em uma série de argumentos.

Responder4

Strace mostra quais são os argumentos usados. Mas o método mais simples para ver o que está sendo processado é adicionar um printf '<%s> 'antes de cada linha relevante e um fechamento echo(para gerar uma nova linha):

Então, a função poderia ser alterada para isto:

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

E quando chamado:

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

É claro que "from sys" está sendo enviado para python como um argumento.
Isso é o que o python recebe, e o python atua "do sys".

informação relacionada