Hybrid code in shell scripts. Sharing variables
Solution 1
The problem with your approach is that the embedded python script no longer has access to the original stdin (since its stdin is... itself).
If that's an issue you can write:
python -c '
import sys;
for r in range(3):
print r
for a in range(2):
print "hello"
'
Or if the python script may contain single quotes:
python -c "$(cat << 'EOF'
import sys;
for r in range(3):
print r
for a in range(2):
print "hello"
EOF
)"
Or:
python <(cat << 'EOF'
import sys;
for r in range(3):
print r
for a in range(2):
print "hello"
EOF
)
Solution 2
Use a dash as the filename:
ruby - a b <<'END'
puts ARGV.join(",")
END
python - a b <<'END'
import sys
print ",".join(sys.argv[1:])
END
I don't know if sys.argv[1:]
is the right way to do this in Python. For -e / -c you can specify end of arguments with --:
set -- -a -b -c
ruby -e 'puts ARGV.join(",")' -- "$@"
python -c 'import sys; print ",".join(sys.argv[2:])' -- "$@"
Capturing output and redirecting STDERR:
x=$(ruby <<'END' 2> /dev/null
puts "a"
abort "b"
END
)
Solution 3
1) You could write variable assignments to a file in python, and then source that in your bash script.
2) Since your word (EOF) is not quoted, all the lines of the here-document are subjected to parameter expansion. You can use this to pass stuff to the python script.
Related videos on Youtube
Amelio Vazquez-Reina
I'm passionate about people, technology and research. Some of my favorite quotes: "Far better an approximate answer to the right question than an exact answer to the wrong question" -- J. Tukey, 1962. "Your title makes you a manager, your people make you a leader" -- Donna Dubinsky, quoted in "Trillion Dollar Coach", 2019.
Updated on September 18, 2022Comments
-
Amelio Vazquez-Reina over 1 year
This answer discusses how to run a multi-line Python snippet from the command line in a terminal. I noticed that the answer works great within shell scripts, even with nested indentation, which is very nice, e.g.
#!/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
prints:
0 hello hello 1 hello hello 2 hello hello
However, I am having a hard time sharing variables between the shell script and the Python snippet.
How can I collect the output of the python subscript in the bash script? (e.g. in a variable such as
$output
).How can I pass a bash variable (e.g.
$some_text
) to the Python script?
-
Admin about 11 yearsYou can do
python - <<EOF
instead. -
Admin about 11 yearsjftr imo this is bad style and you should try to avoid that
-
Admin about 11 yearsWhy the /zsh tag?
-
Admin about 11 yearsThis looks great. When you said
"You could also pass the variable to the script as an argument"
, how would you do that considering that the Python script is embedded within the shell script? -
Admin about 11 yearsSorry, I forgot about that for a second. I have removed that solution and added a better solution.
-
Admin over 8 yearsBe careful how you name the heredoc marker. When it's unquoted as in your example, shell expansion will occur within the heredoc string. For example, if your python code consisted of just
print '$SHELL'
, the output would be/bin/bash
or whatever your shell happens to be. If you change the first line topython - <<'END'
, the output would be$SHELL
. If you are copying and pasting existing code to embed into a bash script, you almost certainly don't want shell substitutions -- you want the code to run the same way it does when it's not embedded in a bash script, right?