
Ich wollte eine kleine Bash-Funktion schreiben, mit der ich „bash“ import os
oder „or “ mitteilen kann, from sys import stdout
und es wird ein neuer Python-Interpreter mit dem importierten Modul erstellt.
Die letztere from
Funktion sieht folgendermaßen aus:
from () {
echo "from $@" | xxd
python3 -i -c "from $@"
}
Wenn ich das aufrufe:
$ 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
>>>
Die Bytes in from sys
sind
66 72 6f 6d 20 73 79 73 20
f r o m s y s
Es gibt dort kein EOF, aber der Python-Interpreter verhält sich, als ob er EOF lesen würde. Am Ende des Streams gibt es eine neue Zeile, was zu erwarten war.
from
Die Schwester von , die ein ganzes Python-Modul importiert, sieht so aus und löst das Problem, indem sie die Zeichenfolge bereinigt und verarbeitet und bei nicht vorhandenen Modulen einen Fehler ausgibt.
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
}
Das löst das Problem eines unerklärlichen EOF im Stream, aber ich würde gerne verstehen, warum Python denkt, dass ein EOF vorliegt.
Antwort1
Der Tisch indiese Stack Overflow-Antwort(das hat es von derBash Hackers Wiki) erklärt, wie die verschiedenen Bash-Variablen erweitert werden:
Sie führen aus python -i -c "from $@"
, was zu wird python -i -c "from sys" "import" "stdout"
und -c
nur ein einziges Argument benötigt, sodass der Befehl ausgeführt wird from sys
. Sie möchten verwenden $*
, was zu erweitert wird python -i -c "from sys import stdout"
(vorausgesetzt, $IFS
es ist nicht festgelegt oder beginnt mit einem Leerzeichen).
Antwort2
strace
zeigt wie immer, was los ist:
bash-4.1$ echo $$
3458
Und anderswo (oder Sie könnten herausfinden, wie strace bash ...
die Funktion aufgerufen wird):
bash-4.1$ strace -ff -o blah -p 3458
Und zurück in dieser ersten Schale:
bash-4.1$ from sys import stdout
File "<string>", line 1
from sys
^
SyntaxError: invalid syntax
>>>
bash-4.1$
Und dann zurück in die 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
Der eigentliche -c
Streit liegt also -c "from sys"
darin, dass „how“ "$@"
erweitert wird oder ein gekürzter Befehl zum python
Absturz kommt.
Antwort3
$@
in Anführungszeichen wird zu einer Liste von Elementen "$1" "$2" "$3"
usw. erweitert.
#!/bin/bash
expand () {
for string in "from $@" ; do
echo "$string"
done
}
expand sys import stdout
Python erwartet, dass der Code aus einem einzigen Argument besteht und nicht aus einer Reihe von Argumenten.
Antwort4
Strace zeigt zwar an, welche Argumente verwendet werden. Die einfachste Methode, um zu sehen, was verarbeitet wird, besteht jedoch darin, printf '<%s> '
vor jeder relevanten Zeile ein und ein abschließendes echo
(als neue Zeile zu generierendes) Zeichen einzufügen:
Die Funktion könnte also folgendermaßen geändert werden:
from () {
printf '<%s> ' "from $@"; echo
printf '<%s> ' python3 -i -c "from $@"; echo
}
Und wenn angerufen wird:
$ from sys import stdout
<from sys> <import> <stdout>
<python3> <-i> <-c> <from sys> <import> <stdout>
Es ist klar, dass „from sys“ als ein Argument an Python gesendet wird.
Das ist, was Python empfängt, und Python reagiert auf „from sys“.