Warum gibt es mitten in den Argumenten ein EOF?

Warum gibt es mitten in den Argumenten ein EOF?

Ich wollte eine kleine Bash-Funktion schreiben, mit der ich „bash“ import osoder „or “ mitteilen kann, from sys import stdoutund es wird ein neuer Python-Interpreter mit dem importierten Modul erstellt.

Die letztere fromFunktion 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 syssind

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.

fromDie 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 -cnur 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, $IFSes ist nicht festgelegt oder beginnt mit einem Leerzeichen).

Antwort2

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

Der eigentliche -cStreit liegt also -c "from sys"darin, dass „how“ "$@"erweitert wird oder ein gekürzter Befehl zum pythonAbsturz 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“.

verwandte Informationen