
Eu queria escrever uma pequena função bash para que eu pudesse dizer ao bash, import os
ou from sys import stdout
ela geraria um novo interpretador Python com o módulo importado.
A última from
funçã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 sys
sã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.
from
A 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 -c
só 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 $IFS
nã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 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
Assim, o argumento real -c
é -c "from sys"
por causa de como "$@"
é expandido ou de um comando truncado que python
continua 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".