Shell脚本中的混合代码。共享变量


10

该答案讨论了如何从终端中的命令行运行多行Python代码段。我注意到,即使在嵌套缩进的情况下,答案在shell脚本中也非常有效,例如,

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

但是,我很难在Shell脚本和Python代码段之间共享变量。

  1. 如何在bash脚本中收集python下标的输出?(例如,在变量中$output)。

  2. 如何将bash变量(例如$some_text)传递给Python脚本?


1
您可以python - <<EOF代替。

jftr imo这是不好的风格,您应该避免这种情况
Ulrich Dangel

1
为什么使用/ zsh标签?
斯特凡Chazelas

Answers:


12

获取Python变量

由于(在EOF未引号的情况下)变量替换发生在文本从heredoc传递到python的标准输入之前,因此您可以在脚本中将变量右移。

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

如果some_text是的话test,python将会看到some_text = "test"。但是请注意,它可以被视为代码注入漏洞。例如,如果some_text是was "; 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
)

(请注意,所有尾随的换行符都将被删除)


这看起来很棒。当您说时"You could also pass the variable to the script as an argument",考虑到Python脚本已嵌入Shell脚本中,您将如何处理?
2013年

抱歉,我忘了那一秒钟。我已经删除了该解决方案,并添加了更好的解决方案。

注意如何命名heredoc标记。如您的示例中未引用该命令时,shell扩展将在heredoc字符串内进行。例如,如果您的python代码由just组成print '$SHELL',则输出为/bin/bash或shell碰巧的任何输出。如果将第一行更改为python - <<'END',输出将为$SHELL。如果要复制并粘贴现有代码以将其嵌入到bash脚本中,则几乎可以肯定不希望使用shell替换-您希望代码以与未嵌入bash脚本时相同的方式运行,对吗?
克里斯·约翰逊

8

您的方法的问题在于,嵌入式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
)

6

使用破折号作为文件名:

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
)

2

1)您可以在python中将变量赋值写入文件,然后在bash脚本中获取该赋值。

2)由于未引用您的单词(EOF),因此本文档的所有行都将进行参数扩展。您可以使用它来将内容传递给python脚本。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.