Perché c'è un EOF nel mezzo degli argomenti?


20

Volevo scrivere una piccola funzione bash in modo tale da poterlo dire import oso from sys import stdoutgenererà un nuovo interprete Python con il modulo importato.

Quest'ultima fromfunzione è simile alla seguente:

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

Se chiamo questo:

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

I byte in from syssono

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

Non c'è EOF, ma l'interprete Python si sta comportando come se leggesse EOF. C'è una nuova riga alla fine del flusso, che è prevedibile.

fromLa sorella, che importa un intero modulo Python, si presenta così e risolve il problema disinfettando ed elaborando la stringa e fallendo sui moduli inesistenti.

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
}

Ciò risolve il problema di un EOF inspiegabile nel flusso, ma vorrei capire perché Python pensa che esista un EOF.

Risposte:


42

La tabella in questa risposta Stack Overflow (che ha ottenuto dal Wiki di Bash Hackers ) spiega come vengono espanse le diverse variabili di Bash:

Stai facendo python -i -c "from $@", che si trasforma in python -i -c "from sys" "import" "stdout"e -caccetta solo un singolo argomento, quindi esegue il comando from sys. Si desidera utilizzare $*, che si espanderà in python -i -c "from sys import stdout"(presupponendo che $IFSnon sia impostato o inizi con uno spazio).


2
Grazie per aver deselezionato, poiché si tratta di informazioni preziose :)
cat

1
Penso che questa dovrebbe essere la risposta accettata poiché in realtà risolve il problema, l'altro votato spiega solo il problema, ma non fornisce soluzioni o soluzioni alternative
Ferrybig,

Buona risposta. Quella tabella in realtà proviene dal Wiki di Bash Hackers. Potresti aggiungere l'attribuzione corretta e verificare di avere il diritto di distribuire?
Corse di leggerezza con Monica,

22

strace, come sempre, mostrerà cosa sta succedendo:

bash-4.1$ echo $$
3458

E altrove (o potresti capire come strace bash ...chiamare la funzione):

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

E di nuovo in quel primo guscio:

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

E poi di nuovo nella 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

Pertanto, l' -cargomento reale è -c "from sys"dovuto al modo in cui "$@"viene espanso o al comando troncato su cui si pythonattiva.


9

$@tra virgolette doppie si espande in un elenco di elementi "$1" "$2" "$3"ecc.

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

expand sys import stdout

Python si aspetta che il codice sia in un argomento, non in una serie di argomenti.


6

Python viene invocato come

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

(vedi la risposta del thrig ).

Per essere $@espanso come una singola stringa (assumendo una sana $IFS), è possibile utilizzare $*all'interno di virgolette doppie:

python3 -i -c "from $*"

Confermato con strace -e execve:

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

2

Strace mostra quali sono gli argomenti utilizzati. Ma il metodo più semplice per vedere cosa viene elaborato è aggiungere un printf '<%s> 'prima di ogni riga pertinente e una chiusura echo(da generare come nuova riga):

Quindi, la funzione potrebbe essere modificata in questo:

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

E quando chiamato:

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

È chiaro che "from sys" viene inviato a Python come unico argomento.
Questo è ciò che Python riceve e Python agisce su "da sys".

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.