Reading a text file from standard input using < - python

I have a Python script which ends the following way:
if __name__ == "__main__":
if len(sys.argv) == 2:
file = open(sys.argv[1])
text = file.readline()
... #more statements
This works when I type in the following: $ python3 script.py my_file.txt
However, I want to change it so my script can accept text from standard input (or even a text file). This is what I want to be able to do:
$ ./script.py < my_file.txt
I think I need to use sys.stdin.read() (or maybe sys.stdin.readlines()). Could you tell me what I would need to change from my original script?
I'm sorry if this looks very basic, but I'm new to Python and I find it hard to see the difference.

It's exactly what you said, you don't need to open a file.
Instead of calling file.readline(), call sys.stdin.readline().
You can make it "nice", with something like:
file = sys.stdin if use_stdin else open(sys.argv[1])

Theres a cool module you can use for this! Assuming you want to do processing per line:
import fileinput
for line in fileinput.input():
process_line(line)

Related

Using Makefile bash to save the contents of a python file

For those who are curious as to why I'm doing this: I need specific files in a tar ball - no more, no less. I have to write unit tests for make check, but since I'm constrained to having "no more" files, I have to write the check within the make check. In this way, I have to write bash(but I don't want to).
I dislike using bash for unit testing(sorry to all those who like bash. I just dislike it so much that I would rather go with an extremely hacky approach than to write many lines of bash code), so I wrote a python file. I later learned that I have to use bash because of some unknown strict rule. I figured that there was a way to cache the entire content of the python file into a single string in the bash file, so I could take the string literal in bash and write to a python file and then execute it.
I tried the following attempt (in the following script and result, I used another python file that's not unit_test.py, so don't worry if it doesn't actually look like a unit test):
toStr.py:
import re
with open("unit_test.py", 'r+') as f:
s = f.read()
s = s.replace("\n", "\\n")
print(s)
And then I piped the results out using:
python toStr.py > temp.txt
It looked something like:
#!/usr/bin/env python\n\nimport os\nimport sys\n\n#create number of bytes as specified in the args:\nif len(sys.argv) != 3:\n print("We need a correct number of args : 2 [NUM_BYTES][FILE_NAME].")\n exit(1)\nn = -1\ntry:\n n = int(sys.argv[1])\nexcept:\n print("Error casting number : " + sys.argv[1])\n exit(1)\n\nrand_string = os.urandom(n)\n\nwith open(sys.argv[2], 'wb+') as f:\n f.write(rand_string)\n f.flush()\n f.close()\n\n
I tried taking this as a string literal and echoing it into a new file and see whether I could run it as a python file but it failed.
echo '{insert that giant string above here}' > new_unit_test.py
I wanted to take this statement above and copy it into my "bash unit test" file so I can just execute the python file within the bash script.
The resulting file looked exactly like {insert giant string here}. What am I doing wrong in my attempt? Are there other, much easier ways where I can hold a python file as a string literal in a bash script?
the easiest way is to only use double-quotes in your python code, then, in your bash script, wrap all of your python code in one pair of single-quotes, e.g.,
#!/bin/bash
python -c 'import os
import sys
#create number of bytes as specified in the args:
if len(sys.argv) != 3:
print("We need a correct number of args : 2 [NUM_BYTES][FILE_NAME].")
exit(1)
n = -1
try:
n = int(sys.argv[1])
except:
print("Error casting number : " + sys.argv[1])
exit(1)
rand_string = os.urandom(n)
# i changed ""s to ''s below -webb
with open(sys.argv[2], "wb+") as f:
f.write(rand_string)
f.flush()
f.close()'

Reading from a file with sys.stdin in Pycharm

I am trying to test a simple code that reads a file line-by-line with Pycharm.
for line in sys.stdin:
name, _ = line.strip().split("\t")
print name
I have the file I want to input in the same directory: lib.txt
How can I debug my code in Pycharm with the input file?
You can work around this issue if you use the fileinput module rather than trying to read stdin directly.
With fileinput, if the script receives a filename(s) in the arguments, it will read from the arguments in order. In your case, replace your code above with:
import fileinput
for line in fileinput.input():
name, _ = line.strip().split("\t")
print name
The great thing about fileinput is that it defaults to stdin if no arguments are supplied (or if the argument '-' is supplied).
Now you can create a run configuration and supply the filename of the file you want to use as stdin as the sole argument to your script.
Read more about fileinput here
I have been trying to find a way to use reading file as stdin in PyCharm.
However, most of guys including jet brains said that there is no way and no support, it is the feature of command line which is not related PyCharm itself.
* https://intellij-support.jetbrains.com/hc/en-us/community/posts/206588305-How-to-redirect-standard-input-output-inside-PyCharm-
Actually, this feature, reading file as stdin, is somehow essential for me to ease giving inputs to solve a programming problem from hackerank or acmicpc.
I found a simple way. I can use input() to give stdin from file as well!
import sys
sys.stdin = open('input.in', 'r')
sys.stdout = open('output.out', 'w')
print(input())
print(input())
input.in example:
hello world
This is not the world ever I have known
output.out example:
hello world
This is not the world ever I have known
You need to create a custom run configuration and then add your file as an argument in the "Script Parameters" box. See Pycharm's online help for a step-by-step guide.
However, even if you do that (as you have discovered), your problem won't work since you aren't parsing the correct command line arguments.
You need to instead use argparse:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("filename", help="The filename to be processed")
args = parser.parse_args()
if args.filename:
with open(filename) as f:
for line in f:
name, _ = line.strip().split('\t')
print(name)
For flexibility, you can write your python script to always read from stdin and then use command redirection to read from a file:
$ python myscript.py < file.txt
However, as far as I can tell, you cannot use redirection from PyCharm as Run Configuration does not allow it.
Alternatively, you can accept the file name as a command-line argument:
$ python myscript.py file.txt
There are several ways to deal with this. I think argparse is overkill for this situation. Alternatively, you can access command-line arguments directly with sys.argv:
import sys
filename = sys.argv[1]
with open(filename) as f:
for line in f:
name, _ = line.strip().split('\t')
print(name)
For robust code, you can check that the correct number of arguments are given.
Here's my hack for google code jam today, wish me luck. Idea is to comment out monkey() before submitting:
def monkey():
print('Warning, monkey patching')
global input
input = iter(open('in.txt')).next
monkey()
T = int(input())
for caseNum in range(1, T + 1):
N, L = list(map(int, input().split()))
nums = list(map(int, input().split()))
edit for python3:
def monkey():
print('Warning, monkey patching')
global input
it = iter(open('in.txt'))
input = lambda : next(it)
monkey()

Python: Echoing to a File (like Bash)

I have a simple bash command here for a script that I am re-writing in Python, and I've done a lot of searching and haven't found a simple answer. I am trying to echo the output of Print to a file, making sure there are no line breaks and that I can pass a variable into it. Here is just a little snippet (there are a lot of lines like this):
echo " ServerName www.${hostName}" >> $prjFile
Now I know it would end up looking something like:
print ("ServerName www.", hostName) >> prjFile
Right? But that doesn't work. Mind you, this is in Python 2.6 (as the machine this script will run on is using that version and there are other dependencies reliant on sticking with that version).
The syntax is;
print >>myfile, "ServerName www.", hostName,
where myfile is a file object opened in mode "a" (for "append").
The trailing comma prevents line breaks.
You might also want to use sys.stdout.softspace = False to prevent the spaces that Python adds between comma-separate arguments to print, and/or to print things as a single string:
print >>myfile, "ServerName www.%s" % hostName,
You can try a simple:
myFile = open('/tmp/result.file', 'w') # or 'a' to add text instead of truncate
myFile.write('whatever')
myFile.close()
In your case:
myFile = open(prjFile, 'a') # 'a' because you want to add to the existing file
myFile.write('ServerName www.{hostname}'.format(hostname=hostname))
myFile.close()

I don't even know what infile > outfile means. How am I supposed to use it?

I don't know how to use Python, and I'm trying to use a script on a document. I have no idea how to tell it do this!
If I just run the script, this is the message I get:
Use: C:\Python27\hun2html.py infile > outfile
Traceback (most recent call last):
File "C:\Python27\hun2html.py", line 75, in <module>
sys.exit(1)
SystemExit: 1
I'm not sure what info is relevant to anyone who knows about this stuff, but this is the most relevant part of the code, I believe:
if __name__ == '__main__':
import sys
if not sys.argv[1:]:
print "Use: %s infile > outfile" % sys.argv[0]
sys.exit(1)
contents = open(sys.argv[1]).read()
print hun2html(contents)
It's supposed to change the formatting in a document. If anyone can make sense of this stupid question, I would really appreciate some help!
It means that you should write the path to the file you want to use for input where infile is and the path to the file you want to store the output where outfile is. For example,
C:\Python27\hun2html.py C:\input.txt > C:\output.txt
Note that the input file is being passed as a parameter (accessed in the code by sys.argv[1] ) and the output is being piped, meaning that the Python prints it to standard output, but because you put the > character it will be redirected to the file you indicate. If you left off the > outfile you would see the output displayed on your terminal.
You give it the input file as the first parameter and redirect the standard output to the file where you want to write the result. For example:
C:\Python27\hun2html.py myfile.hun >myfile.html
The > symbols tells it that whatever gets printed to the standard output will get written to a file, instead of the console. There is also < which will read a file to the standard input.
Suppose you have a document named input.doc. If you run hun2html.py input.doc it will display the output to that terminal.
However, since you want to have the output in another file you'll have to redirect the output to a file. That's where > outfile comes into play. If you want to save the output in output.html, you'll have to do this:
hun2html.py input.doc > output.html
Hope it helps.

How to test a Python script with an input file filled with testcases?

I'm participating in online judge contests and I want to test my code with a .in file full of testcases to time my algorithm. How can I get my script to take input from this .in file?
So the script normally takes test cases from stdin, and now you want to test using test cases from a file?
If that is the case, use the < redirection operation on the cmd line:
my_script < testcases.in
Read from file(s) and/or stdin:
import fileinput
for line in fileinput.input():
process(line)
PyUnit "the standard unit testing framework for Python" might be what you are looking for.
Doing a small script that does something like this:
#!/usr/bin/env python
import sys
def main():
in_file = open('path_to_file')
for line in in_file:
sys.stdout.write(line)
if __name__ == "__main__":
main()
And run as
this_script.py | your_app.py
You can do this in a separate file.
testmyscript.py
import sys
someFile= open( "somefile.in", "r" )
sys.stdin= someFile
execfile( "yourscript.py" )

Categories