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

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

Esta respostadiscute como executar um trecho Python de várias linhas 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 shell script e o snippet Python.

  1. Como posso coletar a saída do subscrito 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?

Responder1

Obtendo uma variável para Python

Como (quando o EOFmarcador não está entre aspas) a substituição da variável ocorre antes do texto ser passado do heredoc para a pythonentrada padrão do , você pode lançar a variável diretamente no script.

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

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

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

e execute esse comando maligno.

Se você quiser extrair seu código Python diretamente em um script sem nenhuma modificação, você pode exportar sua variável.

export some_text

e use os.environpara recuperá-lo.

some_text = os.environ['some_text']

Essa é uma abordagem muito mais sensata/segura.


Obtendo 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 de nova linha finais são removidos)

Responder2

O problema com sua abordagem é que o script python incorporado não tem mais acesso ao stdin original (já que seu stdin é... ele mesmo).

Se isso for 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
)

Responder3

Use um travessão como nome do arquivo:

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

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

Não sei se sys.argv[1:]é a maneira certa de fazer isso em Python. Para -e / -c você pode especificar o final dos argumentos com --:

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

Capturando saída e redirecionando STDERR:

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

Responder4

1) Você pode escrever atribuições de variáveis ​​em um arquivo em python e, em seguida, obtê-las em seu script bash.

2) Como sua palavra (EOF) não está entre aspas, todas as linhas do documento aqui estão sujeitas a expansão de parâmetros. Você pode usar isso para passar coisas para o script python.

informação relacionada