Passing argument to python script within a batch file in Windows - python

I have a python script that can be called in Windows as:
python.exe do_my_work.py param > output.csv
param is an input parameter.
I also have a txt file called params.txt that contains many lines, each line is a value for the parameter of the python script:
hello
world
this
is
test
Because params.txt consists of many many lines, so I would like to write a .batch file that read params.txt line by line then calls python script with the read line as the parameter. The pseudo code as:
open params.txt;
while !eof do:
read a line;
call "python.exe do_my_work.py $line >> output.csv";
end while;
close params.txt;
Could you please show me how to solve this.
P/S: I don't want to change do_my_work.py source code due to some special reasons.

#echo off
set "params=C:\params.txt"
set "output=output.csv"
for /f "usebackq tokens=* delims=" %%# in ("%params%") do (
python do_my_work.py %%# 1>>"%output%"
)

Related

Is there a way to have Windows task scheduler automatically respond to input() in Python script?

I'm trying to schedule a python script to run automatically on a Windows 10 machine. The script, when run alone, prompts the user for some input to use as it runs. I'd like to automatically set these inputs when the scheduler runs the .bat file. As an example:
test.py:
def main():
name = input('What is your name? ')
print(f'Hello, {name}. How are you today?')
main()
This works fine if I just run the script, but ideally I'd like to have the name variable passed to it from the .bat file.
test.bat:
"path\to\python.exe" "path\to\test.py"
pause
Any help would be greatly appreciated!
If you just want to give a single fixed input, you can do it like:
REM If you add extra spaces before `|` those will be passed to the program
ECHO name_for_python| "path\to\python.exe" "path\to\test.py"
Unfortunately, there is no good way of extending this to multiple lines. You would use a file containing the lines you want to input for that:
"path\to\python.exe" "path\to\test.py" < file_with_inputs.txt
If you want to have everything into a standalone script, you may do something like this:
REM Choose some path for a temporary file
SET temp_file=%TEMP%\input_for_my_script
REM Write input lines to file, use > for first line to make sure file is cleared
ECHO input line 1> %temp_file%
REM Use >> for remaining lines to append to file
ECHO input line 2>> %temp_file%
ECHO input line 3>> %temp_file%
REM Call program with input file
"path\to\python.exe" "path\to\test.py" < file_with_inputs.txt
REM Delete the temporary file
DEL %temp_file% /q
Obviously, this is assuming you cannot use the standard sys.argv (or extensions like argparse), which would be the more standard and convenient way to send arguments to a script.

Safely echo python commands into file without executing them

So I have a python file with a ton of lines in it that I want to read into python then echo into another file over a socket.
Assuming I have file foo.py
import os
os.popen('some command blah')
print("some other commands, doesn't matter")
Then I try and open the file, read all the lines, and echo each line into a new file.
Something along the lines of
scriptCode = open(os.path.realpath(__file__)).readlines()
for line in scriptCode:
connection.send("echo " + line + " >> newfile.py")
print("file transfered!")
However, when I do this, the command is executed in the remote shell.
So my question:
How do I safely echo text into a file without executing any keywords in it?
What have I tried?
Adding single quotes around line
Adding single quotes around line and then a backslash to single quotes in line
Things I've considered but haven't tried yet:
Base64 encoding the line until on the remote machine then decoding it (I don't want to do this because there's no guarentee it'll have this command)
I know this is odd. Why am I doing this?
I'm building a pentesting reverse shell handler.
shlex.quote will:
Return a shell-escaped version of the string s. The returned value is a string that can safely be used as one token in a shell command line, for cases where you cannot use a list.
Much safer than trying to quote a string by yourself.

mac os: How do I run a multi-line script on command line?

I have a python file that isn't working.
I would like to run this script on it:
with open('beak', 'rb+') as f:
content = f.read()
f.seek(0)
f.write(content.replace(b'\r', b''))
f.truncate()
Source
I don't know how to make multiple lines on command line and I am not really sure how to execute my code. Do I just put my file name in place of 'beak' and do I just cd to the folder my file is in before I execute this script?
You can type that into the Python command line. Type the first line and return, it will recognize that you're in the middle of a with clause and allow you to type the remaining lines one at a time (be sure to get the indentation right). After the last line, return twice and it will execute.
This script assumes that you are going to read a file named "beak". You need to run this script from the same directory where "beak" is. ("beak" should really have an extension, like ".txt", depending on what kind of file it is).
Doing long scripts from the command line like this is not the best way -- it's better to put this code in a file ("reader.py", for example -- and put reader.py in the same directory as "beak"). Then you can simply execute by typing "python reader.py".

Modify string in bash to contain new line character?

I am using a bash script to call google-api's upload_video.py (https://developers.google.com/youtube/v3/guides/uploading_a_video )
I have a mp4 called output.mp4 which I would like to upload.
The problem is I cannot get my array to work how I would like.
This new line character is "required" because my arguments to python script contain spaces.
Here is a simplified version of my bash script:
# Operator may change these
hold=100
location="Foo, Montana "
declare -a file_array=("unique_ID_0" "unique_ID_1")
upload_file=upload_file.txt
upload_movie=output.mp4
# Hit enter at end b/c \n not recognized
upload_title=$location' - '${file_array[0]}' - Hold '$hold' Sweeps
'
upload_description='The spectrum recording was made in at '$location'.
'
# Overwrite with 1st call > else apppend >>
echo "$upload_title" > $upload_file
echo "$upload_description" >> $upload_file
# Load each line of text file into array
IFS=$'\n'
cmd_google=$(<$upload_file)
unset IFS
nn=1
for i in "${cmd_google[#]}"
do
echo "$i"
# Delete last character: \n
#i=${i[-nn]%?}
#i=${i: : -nn}
#i=${i::${#i}-nn}
i=${i%?}
#i=${i#"\n"}
#i=${i%"\n"}
echo "$i"
done
python upload_video.py --file=$upload_movie --title="${cmd_google[0]}" --description="${cmd_google[1]}"
At first I attempted to remove the new line character, but it appears that the enter or \n is not working how I would like, each line is not separate. It writes the title and description as one line.
How do I modify my bash script to recognize a newline character?
This is much simpler than you are making it.
# Operator may change these
hold=100
location="Foo, Montana"
declare -a file_array=("unique_ID_0" "unique_ID_1")
upload_file=upload_file.txt
upload_movie=output.mp4
upload_title="$location - ${file_array[0]} - Hold $hold Sweeps"
upload_description="The spectrum recording was made in at $location."
cat <<EOF > "$upload_file"
$upload_title
$upload_description
EOF
# ...
readarray -t cmd_google < "$upload_file"
python upload_video.py --file="$upload_movie" --title="${cmd_google[0]}" --description="${cmd_google[1]}"
I suspect the readarray command is all you are really looking for, since much of the above code is simply creating a file that I assume you are receiving already created.
I figured it out with help from chepner's answer. My question hid the fact that I wanted to write new line characters into the video's description.
Instead of adding a new line character in the bash script, it is much easier to have a text file which contains the correctly formatted script and read it in, then concatenate it with run-time specific variable.
In my case the correctly formatted text is called description.txt:
Here is a snip of my description.txt which contains newline characters
Here is my final version of the script:
# Operator may change these
hold=100
location="Foo, Montana"
declare -a file_array=("unique_ID_0" "unique_ID_1")
upload_title="$location - ${file_array[0]} - Hold $hold Sweeps"
upload_description="The spectrum recording was made in at $location. "
# Read in script which contains newline
temp=$(<description.txt)
# Concatenate them
upload_description="$upload_description$temp"
upload_movie=output.mp4
python upload_video.py --file="$upload_movie" --title="$upload_title" --description="$upload_description"

Can Gnuplot take different arguments at run time? maybe with Python?

I have 500 files to plot and I want to do this automatically. I have the gnuplot script
that does the plotting with the file name hard coded. I would like to have a loop that calls gnuplot every iteration with a different file name, but it does not seem that gnuplot support command line arguments.
Is there an easy way? I also installed the gnuplot-python package in case I can do it via a python script.However, I couldn't find the api so it's a bit difficult to figure out.
Thank you!
You can transform your gnuplot script to a shell script by prepending the lines
#!/bin/sh
gnuplot << EOF
appending the line
EOF
and substituting every $ by \$. Then, you can substitute every occurence of the filename by $1 and call the shell script with the filename as parameter.
Regarding the $'s in Sven Marnach's solution (the lines between EOF are called a "here script" in shell parlance): in my experience, one uses shell variables as usual, but $s that are meant for gnuplot itself must be escaped.
Here is an example:
for distrib in "uniform" "correlated" "clustered"
do
gnuplot << EOF
# gnuplot preamble omitted for brevity
set output "../plots/$distrib-$eps-$points.pdf"
set title "$distrib distribution, eps = $eps, #points = $points"
plot "../plots/dat/$distrib-$eps-$points.dat" using 1:(\$2/$points) title "exact NN"
EOF
done
Note the backslash escaping the dollar so that gnuplot sees it.
A simple way is to generate 500 gnuplot scripts like so:
for filename in list_of_files:
outfile = open(filename + '-script', 'w')
outfile.write(script_text % (filename,))
where script_text is the text of your gnuplot script with the filename replaced with a %s.
I've done this some times. But don't use EOF, because you cannot write on bash inside the << EOF and EOF tags. Depending on the names of the files you can do it in diferent ways.
a) If the filenames are loopable (sort of 1.dat 2.dat 3.dat, etc.)
#!/bin/bash
for((i=0;i<1;i++)) do
echo "plot '-' u 1:2"
for((j=1;j<=3;j++)) do
cat $i.dat
echo "e"
done
done | gnuplot -persist
The first loop is a kind of buffer to feed it all to gnuplot.
b) If the filenames aren't loopable (such as ñlasjkd.dat ajñljd.mov añlsjkd.gif) you first need to move them to a new folder. Then do
#!/bin/bash
ffiles=$(ls | xargs) # a list of the folder's files
# Use the list to pipe all the data to gnuplot using cat
for((i=0;i<1;i++)) do
echo "plot '-' u 1:2 w lp";
cat $ffiles;
echo "e";
done | gnuplot -persist
c) If you want some more, that is: to keep the information of the separated files just on one file... but maintaning the datasheets alive use "index" of gnuplot (if gnuplot reads two black lines guesses that is another datasheet)
#!/bin/bash
ffiles=$(ls|xargs)
ls $ffiles > ffiles.list # A file with the folder's files
while read line
do
cat $line;
echo -e; echo -e;
done < ffiles.list > alldata.dat
# ^-feeding ffiles.list to the while loop
# and writing the file alldata.dat
now you can go to gnuplot and acces to one datasheet
plot 'alldata.dat' index 1 u 1:2
and you will see the first file appearing on the list "ffiles.list". If you whant to see more than one, say 4
plot 'alldata.dat' index 1:4 u 1:2
tricky but easy.
Unless I'm misunderstanding your question, there's an easier way.
In the gnuplot script, replace all occurrences of your filename with $0.
Then in bash, loop over your plot files (let's say they are .txt files in $plotsDir) and call gnuplot:
for f in "$plotsDir/*.txt"; do
echo "call '$f'" | gnuplot
done
Here is one way to do this. Your gnuplot input file, say plot.gp, contains a line
plot "data"
or something like that. Save the lines before this line in plot1.gp and the lines after this line in plot2.gp. Now call gnuplot as
gnuplot plot1.gp -e `plot "data"` plot2.gp
which facilitates passing the name of data on the command line.
I create a file named test.txt containing plot [0:20] x;
I run gnuplot test.txt and I see that gnuplot has indeed read contents of my file, so it does support arguments at runtime.
Different methods of solving this problem are also covered in How to pass command line argument to gnuplot? :
Using -e
Using -c or call with ARG0 like variables (gnuplot >= 5)
Using call with $0 like variables (gnuplot <= 4.6.6)
Using environment variables and system()
Piping the program into gnuplot

Categories

Resources