Codice ibrido negli script di shell. Condivisione di variabili


10

Questa risposta spiega come eseguire uno snippet Python multilinea dalla riga di comando in un terminale. Ho notato che la risposta funziona benissimo negli script di shell, anche con rientri nidificati, il che è molto bello, ad es

#!/bin/bash
some_text="Hello world"
echo $some_text

cat <<EOF | python -
import sys;
for r in range(3):
  print r
  for a in range(2):
    print "hello"
EOF

stampe:

0 
hello
hello
1
hello
hello
2
hello
hello

Tuttavia, faccio fatica a condividere le variabili tra lo script della shell e lo snippet di Python.

  1. Come posso raccogliere l'output del pedice python nello script bash? (ad es. in una variabile come $output).

  2. Come posso passare una variabile bash (ad es. $some_text) Allo script Python?


1
Puoi fare python - <<EOFinvece.

jftr imo questo è un cattivo stile e dovresti cercare di evitarlo
Ulrich Dangel,

1
Perché il tag / zsh?
Stéphane Chazelas,

Risposte:


12

Ottenere una variabile su Python

Poiché (quando il EOFmarker non è citato) la sostituzione della variabile avviene prima che il testo venga passato dall'ereditarietà allo pythonstandard input, è possibile lanciare la variabile direttamente nello script.

python - <<EOF
some_text = "$some_text"
EOF

Se lo some_textfosse test, Python avrebbe visto some_text = "test". Si noti tuttavia che può essere visto come una vulnerabilità di iniezione di codice. Se some_textfosse "; import os; os.system("evil-command"); x = ", ad esempio, Python vedrebbe:

some_text = ""; import os; os.system("evil-command"); x = ""

ed esegui quel comando malvagio.

Se vuoi essere in grado di estrarre il tuo codice Python direttamente in uno script senza alcuna modifica, puoi esportare la tua variabile.

export some_text

e utilizzarlo os.environper recuperarlo.

some_text = os.environ['some_text']

Questo è un approccio molto più sano / sicuro.


Ottenere output da Python

È possibile utilizzare la sostituzione dei comandi per raccogliere l'output dello script.

output=$(
python - <<EOF
import sys;
for r in range(3):
  print r
  for a in range(2):
    print "hello"
EOF
)

(nota che tutti i caratteri di nuova riga finali vengono rimossi)


Questo sembra fantastico. Quando hai detto "You could also pass the variable to the script as an argument", come lo faresti considerando che lo script Python è incorporato nello script shell?
Amelio Vazquez-Reina,

Scusa, me ne sono dimenticato per un secondo. Ho rimosso quella soluzione e ho aggiunto una soluzione migliore.

Fai attenzione a come chiami il marcatore ereditario. Quando non è quotato come nel tuo esempio, l'espansione della shell avverrà all'interno della stringa ereditaria. Ad esempio, se il tuo codice python consistesse in just print '$SHELL', l'output sarebbe /bin/basho qualunque sia la tua shell. Se si cambia la prima riga in python - <<'END', l'output sarebbe $SHELL. Se stai copiando e incollando il codice esistente da incorporare in uno script bash, quasi sicuramente non vuoi sostituzioni di shell - vuoi che il codice venga eseguito allo stesso modo in cui non è incorporato in uno script bash, giusto?
Chris Johnson,

8

Il problema con il tuo approccio è che lo script Python incorporato non ha più accesso allo stdin originale (poiché il suo stdin è ... stesso).

Se questo è un problema puoi scrivere:

python -c '
import sys;
for r in range(3):
  print r
  for a in range(2):
    print "hello"
'

O se lo script python può contenere virgolette singole:

python -c "$(cat << 'EOF'
import sys;
for r in range(3):
  print r
  for a in range(2):
    print "hello"
EOF
)"

O:

python <(cat << 'EOF'
import sys;
for r in range(3):
  print r
  for a in range(2):
    print "hello"
EOF
)

6

Usa un trattino come nome file:

ruby - a b <<'END'
puts ARGV.join(",")
END

python - a b <<'END'
import sys
print ",".join(sys.argv[1:])
END

Non so se sys.argv[1:]sia il modo giusto per farlo in Python. Per -e / -c è possibile specificare la fine degli argomenti con -:

set -- -a -b -c
ruby -e 'puts ARGV.join(",")' -- "$@"
python -c 'import sys; print ",".join(sys.argv[2:])' -- "$@"

Catturare output e reindirizzare STDERR:

x=$(ruby <<'END' 2> /dev/null
puts "a"
abort "b"
END
)

2

1) Potresti scrivere assegnazioni di variabili su un file in Python, e quindi crearlo nel tuo script bash.

2) Poiché la tua parola (EOF) non è citata, tutte le righe del documento qui sono soggette all'espansione dei parametri. Puoi usarlo per passare elementi allo script Python.

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.