Гибридный код в скриптах оболочки. Совместное использование переменных

Гибридный код в скриптах оболочки. Совместное использование переменных

Этот ответобсуждает, как запустить многострочный фрагмент Python из командной строки в терминале. Я заметил, что ответ отлично работает в скриптах оболочки, даже с вложенными отступами, что очень хорошо, например

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

отпечатки:

0 
hello
hello
1
hello
hello
2
hello
hello

Однако у меня возникли трудности с разделением переменных между скриптом оболочки и фрагментом Python.

  1. Как собрать вывод скрипта Python в скрипте Bash? (например, в переменной, такой как $output).

  2. Как передать переменную bash (например $some_text, ) в скрипт Python?

решение1

Получение переменной в Python

Поскольку (когда EOFмаркер не заключен в кавычки) подстановка переменных происходит до того, как текст передается из heredoc в pythonстандартный ввод, вы можете вставить переменную прямо в скрипт.

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

Если some_textбыло test, python увидел бы some_text = "test". Однако следует отметить, что это можно рассматривать как уязвимость внедрения кода. Если some_textбыло "; import os; os.system("evil-command"); x = ", например, python увидел бы:

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

и выполнить эту злую команду.

Если вы хотите иметь возможность вставить свой код Python прямо в скрипт без каких-либо изменений, вы можете экспортировать свою переменную.

export some_text

и используйте os.environдля его извлечения.

some_text = os.environ['some_text']

Это гораздо более разумный и безопасный подход.


Получение вывода из Python

Для сбора выходных данных скрипта можно использовать подстановку команд.

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

(обратите внимание, что все конечные символы новой строки удаляются)

решение2

Проблема вашего подхода в том, что встроенный скрипт Python больше не имеет доступа к исходному stdin (поскольку его stdin — это... он сам).

Если это проблема, вы можете написать:

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

Или если скрипт Python может содержать одинарные кавычки:

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

Или:

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

решение3

Используйте тире в качестве имени файла:

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

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

Я не знаю, sys.argv[1:]правильно ли это сделать в Python. Для -e / -c вы можете указать конец аргументов с помощью --:

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

Захват вывода и перенаправление STDERR:

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

решение4

1) Вы можете написать присваивание переменных файлу на Python, а затем передать это в свой скрипт Bash.

2) Поскольку ваше слово (EOF) не заключено в кавычки, все строки here-document подвергаются расширению параметров. Вы можете использовать это для передачи чего-либо в скрипт python.

Связанный контент