I have a Perl script from which I am calling a Python script.
I am using:
system "python script.py '".$var1."' '".$var2."' '".$var3."' '".$var4."' '".$var5."'";
Where, $var1 = "'Nostoc azollae' 0708", which has single quotes in the string.
In the script.py script, I am using:
var1 = sys.argv[1]
And if I print var1, it only prints: Nostoc and the rest is not printed, rest is working fine.
So, clearly the Python script is not receiving the string with the ' included.
What can be a solution to this?
Avoid shell invocation when using system() by using separate parameters instead of joining them all together,
system("python", "script.py", $var1, $var2, $var3, $var4, $var5);
Related
I'm trying to get multiple variables from Python to be usable as variables within Bash. Although I have python as the source, it could be any programme/script, but not a file.
I can get source to do the job with a temp file. So I guess the question is, how do I pipe from a script output to source?
The source python could output any and/or multiple key=value so simply x=$(python script) does not work.
Python snip example
print("STARTDATE=" + STARTDATE)
print("STARTTIME=" + STARTTIME)
Output
STARTDATE=06/15/2021
STARTTIME=15:46:21.00
Bash working example with temp file
python script > temp.file
source temp.file
echo $STARTDATE
Echo is just for debugging here, I would be doing work on the variables
Failed attempts:
source python script
source <(python script)
eval $(python script)
You will need spaces around the strings and will also need to ensure that there are no spaces before or after "=" and so:
print("STARTDATE=\"" + STARTDATE + "\"")
print("STARTTIME=\"" + STARTTIME + "\"")
Making sure that you are using a bash shell and not sh, you should then be able to action the script and set the variables with:
source <(./script.py)
Or in a script:
#!/bin/bash
source <(./script.py)
I've found that python can run other programs using the subprocess module. I want to use python to run a powershell script that is in a directory location that contains spaces. How do I handle the spaces in the python script below?
import subprocess
powershellExeLocation = r"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
powershellScriptLocation = r"C:\Users\username\Documents\testPowershell.ps1"
print('running script with no spaces')
#this works
subprocess.run([powershellExeLocation, powershellScriptLocation])
#this doesn't work
print('running script with spaces')
powershellScriptLocationWithSpaces = r"C:\Users\username\path with spaces\testPowershell.ps1"
subprocess.run([powershellExeLocation, powershellScriptLocationWithSpaces])
Try this:
subprocess.run([powershellExeLocation, "-File", powershellScriptLocationWithSpaces])
The script location needs a set of literal quotes around it, so powershell.exe knows to treat it as one single filename.
subprocess.run([powershellExeLocation, '"' + powershellScriptLocationWithSpaces + '"'])
I have a simple shell script script.sh:
echo "ubuntu:$1" | sudo chpasswd
I need to open the script, read it, insert the argument, and save it as a string like so: 'echo "ubuntu:arg_passed_when_opening" | sudo chpasswd' using Python.
All the options suggested here actually execute the script, which is not what I want.
Any suggestions?
You would do this the same way that you read any text file, and we can use sys.argv to get the argument passed when running the python script.
Ex:
import sys
with open('script.sh', 'r') as sfile:
modified_file_contents = sfile.read().replace('$1', sys.argv[1])
With this method, modified_file_contents is a string containing the text of the file, but with the specified variable replaced with the argument passed to the python script when it was run.
I have an awk command that works in bash, but im now trying to put it into a python script
I have tried both os.system, and subprocess.call both return the same error. sh: 1: Syntax error: "(" unexpected
os.system('awk \'FNR<=27{print;next} ++count%10==0{print;count}\' \'{0} > {1}\'.format(inputfile, outpufile)')
So this awk command will take the large inputfile and create an output file that leaves the first 27 lines of header, but then starting on line 28 it only takes every 10th line and puts it into the output file
Im using the .format() because it is within a python script where the input file will be different every times its run.
ive also tried
subprocess.call('awk \'FNR<=27{print;next} ++count%10==0{print;count}\' \'{0} > {1}\'.format(inputfile, outpufile)')
both come up with the same error above. What am I missing?
As per the comment above, probably more pythonic (and more manageable) to directly use python.
But, if you want to use awk then one way is to format your command with your variable filenames separately.
This works using a basic test text file:
import os
def awk_runner(inputfile, outputfile):
cmd = "awk 'FNR<=27{print;next} ++count%10==0{print;count}' " + inputfile + " > " + outputfile
os.system(cmd)
awk_runner('test1.txt', 'testout1.txt')
There are two main issues with your Python code:
format() is a python method call, it should not be put into the string of awk_cmd to execute under the shell
when calling format() method, braces {} are used to identify substitution target in the format string objects, they need to be escaped using {{ ... }}
See below a modified version of your code:
awk_cmd = "awk 'FNR<=7{{print;next}} ++count%10==0{{print;count}}' {0} > {1}".format(inputfile, outpufile)
os.system(awk_cmd)
I am trying to run some piece of Python code in a Bash script, so i wanted to understand what is the difference between:
#!/bin/bash
#your bash code
python -c "
#your py code
"
vs
python - <<DOC
#your py code
DOC
I checked the web but couldn't compile the bits around the topic. Do you think one is better over the other?
If you wanted to return a value from Python code block to your Bash script then is a heredoc the only way?
The main flaw of using a here document is that the script's standard input will be the here document. So if you have a script which wants to process its standard input, python -c is pretty much your only option.
On the other hand, using python -c '...' ties up the single-quote for the shell's needs, so you can only use double-quoted strings in your Python script; using double-quotes instead to protect the script from the shell introduces additional problems (strings in double-quotes undergo various substitutions, whereas single-quoted strings are literal in the shell).
As an aside, notice that you probably want to single-quote the here-doc delimiter, too, otherwise the Python script is subject to similar substitutions.
python - <<'____HERE'
print("""Look, we can have double quotes!""")
print('And single quotes! And `back ticks`!')
print("$(and what looks to the shell like process substitutions and $variables!)")
____HERE
As an alternative, escaping the delimiter works identically, if you prefer that (python - <<\____HERE)
If you are using bash, you can avoid heredoc problems if you apply a little bit more of boilerplate:
python <(cat <<EoF
name = input()
print(f'hello, {name}!')
EoF
)
This will let you run your embedded Python script without you giving up the standard input. The overhead is mostly the same of using cmda | cmdb. This technique is known as Process Substitution.
If want to be able to somehow validate the script, I suggest that you dump it to a temporary file:
#!/bin/bash
temp_file=$(mktemp my_generated_python_script.XXXXXX.py)
cat > $temp_file <<EoF
# embedded python script
EoF
python3 $temp_file && rm $temp_file
This will keep the script if it fails to run.
If you prefer to use python -c '...' without having to escape with the double-quotes you can first load the code in a bash variable using here-documents:
read -r -d '' CMD << '--END'
print ("'quoted'")
--END
python -c "$CMD"
The python code is loaded verbatim into the CMD variable and there's no need to escape double quotes.
How to use here-docs with input
tripleee's answer has all the details, but there's Unix tricks to work around this limitation:
So if you have a script which wants to process its standard input, python -c is pretty much your only option.
This trick applies to all programs that want to read from a redirected stdin (e.g., ./script.py < myinputs) and also take user input:
python - <<'____HERE'
import os
os.dup2(1, 0)
print(input("--> "))
____HERE
Running this works:
$ bash heredocpy.sh
--> Hello World!
Hello World!
If you want to get the original stdin, run os.dup(0) first. Here is a real-world example.
This works because as long as either stdout or stderr are a tty, one can read from them as well as write to them. (Otherwise, you could just open /dev/tty. This is what less does.)
In case you want to process inputs from a file instead, that's possible too -- you just have to use a new fd:
Example with a file
cat <<'____HERE' > file.txt
With software there are only two possibilites:
either the users control the programme
or the programme controls the users.
____HERE
python - <<'____HERE' 4< file.txt
import os
for line in os.fdopen(4):
print(line.rstrip().upper())
____HERE
Example with a command
Unfortunately, pipelines don't work here -- but process substitution does:
python - <<'____HERE' 4< <(fortune)
import os
for line in os.fdopen(4):
print(line.rstrip().upper())
____HERE