Código híbrido em scripts de shell. Compartilhando Variáveis

9

Esta resposta discute como executar um snippet de várias linhas do Python a partir da linha de comando em um terminal. Percebi que a resposta funciona muito bem em scripts de shell, mesmo com recuo aninhado, o que é muito bom, por exemplo

#!/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

impressões:

0 
hello
hello
1
hello
hello
2
hello
hello

No entanto, estou tendo dificuldade em compartilhar variáveis entre o script de shell e o snippet do Python.

  1. Como posso coletar a saída do subscrito do python no script bash? (por exemplo, em uma variável como $output ).

  2. Como posso passar uma variável bash (por exemplo, $some_text ) para o script Python?

por Amelio Vazquez-Reina 30.04.2013 / 23:47

4 respostas

11

Como obter uma variável para o Python

Como (quando o marcador EOF não é citado) a substituição da variável ocorre antes que o texto seja passado do heredoc para a entrada padrão do python , você pode lançar a variável diretamente no script.

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

Se some_text fosse test , o python veria some_text = "test" . Observe, no entanto, que ele pode ser visto como uma vulnerabilidade de injeção de código. Se some_text fosse "; import os; os.system("evil-command"); x = " , por exemplo, o python veria:

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

e execute esse comando maligno.

Se você quiser colocar seu código Python em um script sem modificações, poderá exportar sua variável.

export some_text

e use os.environ para recuperá-lo.

some_text = os.environ['some_text']

Essa é uma abordagem muito mais saudável e segura.

Obtendo a saída do Python

Você pode usar a substituição de comando para coletar a saída do script.

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

(observe que todos os caracteres da nova linha são removidos)

    
por 01.05.2013 / 00:09
7

O problema com a sua abordagem é que o script python embutido não tem mais acesso ao stdin original (já que o próprio stdin é ...).

Se isso é um problema, você pode escrever:

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

Ou se o script python puder conter aspas simples:

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

Ou:

python <(cat << 'EOF'
import sys;
for r in range(3):
  print r
  for a in range(2):
    print "hello"
EOF
)
    
por 01.05.2013 / 22:42
5

Use um traço como o nome do arquivo:

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

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

Eu não sei se sys.argv[1:] é o caminho certo para fazer isso em Python. Para -e / -c você pode especificar o fim dos argumentos com -:

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

Captura de saída e redirecionamento de STDERR:

x=$(ruby <<'END' 2> /dev/null
puts "a"
abort "b"
END
)
    
por 01.05.2013 / 07:11
2

1) Você poderia escrever atribuições de variáveis para um arquivo em python e, em seguida, fonte que em seu script bash.

2) Como sua palavra (EOF) não é citada, todas as linhas do documento here são submetidas à expansão de parâmetro. Você pode usar isso para passar coisas para o script python.

    
por 01.05.2013 / 00:08