Python and Bash: how to automate user input? - python

I downloaded some scripts in both python and bash that prompt the user for command line input. Since I run these scripts often, I would like to automatically supply the input to the programs. I prefer not to modify the scripts. Is there a way to do it without modifying the original code?
[UPDATE] thanks to EnabrenTane's advice, it seems to work pretty well, until I got to a line that read password = getpass.getpass('password: '). It complains the following:
File "/usr/lib/python2.4/getpass.py", line 29, in unix_getpass
old = termios.tcgetattr(fd) # a copy to save
termios.error: (25, 'Inappropriate ioctl for device')
Any way to get around that?

Like this on bash: $ ./python_script < input.txt
edit:
Alternatively you could write your scripts to take ARGV as a file name to read from. You could reopen STDIN to the file and not have to change any other lines.

Since the responses in via stdin:
cat answers | yourscript.py

Due to the password requirement, I ended up using pexpect, a python module that automates user input.

Related

How do I let Python see what Terminal outputs when I enter a command?

I want to run a program on Python on macOS Sierra that checks Terminal for its outputs after I automatically enter a command on it. For example, I would write in Terminal:
$ pwd
and then Terminal would output something like:
/Users/username
How would I have Python scan what Terminal outputs and set it to a variable as a string?
>>>output = (whatever Terminal outputs)
>>>print (output)
"/Users/username"
By the way, the other forums do not explain in much detail how one would do this in macOS. Therefore, this is not a duplicate of any forum.
You could pipe the output to a file and read the file.
$ pwd > output.txt
Then read the file and take further actions based on its contents.
Use the subprocess module, it has some shortcut methods to make things easier and less complicated than using Popen.
>>> import subprocess
>>> output = subprocess.check_output("pwd")
>>> print(output)
b'L:\\\r\n'
You can decode this using output.decode("UTF-8") if you like or you can use the universal_newlines keyword argument to have it done automatically as well as sorting out newlines.
>>> subprocess.check_output("pwd", universal_newlines=True)
'L:\\\n'
Edit: With #Silvio's sensible suggestion, passing all arguments you can do the following:
subprocess.check_output(["ls", "-l"])
Or if you have a string sourced from elsewhere you can call .split() which will generate a list of substrings separated by a space.
subprocess.check_output("ls -l /".split())
Note: I'm using Python3 on Windows and Gnu on Windows so I have \r\n line endings and pwd.

Python3: Using input() with stdin, like in hackerrank

I have an input file ("abc.in") which I will like to read each line as input(), exactly like how it works on hackerrank and other online coding platforms.
I have seen solutions replicating the same functionality by piping, fileinput and sys etc. On hackerrank I can just use input() to store one line of the input file as a variable. How do I do that locally? Do I store the files in the same place, what command do I use to run this in the terminal?
I thought this would be easy, but somehow I can't seem to figure out how to do it after trying for some time. Apologies if the answer was obvious.
Any help provided is greatly appreciated!
You can redirect the stdin with < on command line. Let's say you have following input stored to file data.in:
line1
line2
And you have following code stored to test.py:
print(1, input())
print(2, input())
Then you can run the script with redirected stdin:
~$ python3 test.py < data.in
1 line1
2 line2
If you want to save the output to a file you can redirect stdout as well:
~$ python3 test.py < data.in > data.out

Why doesn't my bash script read lines from a file when called from a python script?

I am trying to write a small program in bash and part of it needs to be able to get some values from a txt file where the different files are separated by a line, and then either add each line to a variable or add each line to one array.
So far I have tried this:
FILE=$"transfer_config.csv"
while read line
do
MYARRAY[$index]="$line"
index=$(($index+1))
done < $FILE
echo ${MYARRAY[0]}
This just produces a blank line though, and not what was on the first line of the config file.
I am not returned with any errors which is why I am not too sure why this is happening.
The bash script is called though a python script using os.system("$HOME/bin/mcserver_config/server_transfer/down/createRemoteFolder"), but if I simply call it after the python program has made the file which the bash script reads, it works.
I am almost 100% sure it is not an issue with the directories, because pwd at the top of the bash script shows it in the correct directory, and the python program is also creating the data file in the correct place.
Any help is much appreciated.
EDIT:
I also tried the subprocess.call("path_to_script", shell=True) to see if it would make a difference, I know it is unlikely but it didn't.
I suspect that when calling the bash script from python, having just created the file, you are not really finished with that file: you should either explicitly close the file or use a with construct.
Otherwise, the written data is still in any buffer (from the file object, or in the OS, or wherever). Only closing (or at least flushing) the file makes sure the data is indeed in the file.
BTW, instead of os.system, you should use the subprocess module...

Syntax for input redirection in IDLE

I need to enter the contents of a text (.txt) file as input for a Python (.py) file. Assuming the name of the text file is TextFile and the name of the Python file PythonFile, then the code should be as follows:
python PythonFile.py < TextFile.txt
Yet, when I try to do this in IDLE and type in
import PythonFile < TextFile,
IDLE gives me an invalid syntax message, pointing to the < sign. I tried all sorts of variations on this theme (i.e.,using or not using the file name extensions), but still got the same invalid-syntax message. How is the syntax different for input redirection in IDLE?
If it works in the command line, then why do you want to do this in IDLE? There are ways to achieve a similar result using, for example, subprocess, but a better way would be to refactor PythonFile.py so that you can call a function from it, e.g.:
>>> import PythonFile
>>> PythonFile.run_with_input('TextFile.txt')
If you post the contents of PythonFile.py, we might be able to help you do this.

Are my permissions set correctly? (python)

In python I'm doing a os.system('chmod o+w filename.png') command so I can overwrite the file with pngcrush.
These are the permissions after I set them in python:
-rw-rw-rw- 1 me users 925 Sep 20 11:25 filename.png
Then I attempt:
os.system('pngcrush filename.png filename.png')
which is supposed to overwrite the file, but I get:
Cannot overwrite input file filename.png
What could be the problem? Isn't pngcrush being run as an 'other' user, for which write permissions are enabled?
Thanks!
The problem is with the way you execute the pngcrush program, not with permissions of filename.png or Python. It simply attempts to open filename.png both for input and output, which is of course invalid.
Give pngcrush either the -e or the -d option to tell it how to write output. Read its man for more information.
Perhaps pngcrush isn't letting you use the same name for both input and output files? Have you tried changing the output filename? If so, what were the results?
As an aside (not related to the problem of the input and output files being the same), you can change the mode of a file using os.chmod, which is more efficient than running chmod:
import os
import stat
path = "filename.png"
mode = os.stat(path).st_mode # get current mode
newmode = mode | stat.S_IWOTH # set the 'others can write' bit
os.chmod(path, newmode) # set new mode
Perhaps you're supposed to give a different (non-existing) filename for output. Have you tried the same in a shell?

Categories