How to write the output of a os.walk to file - python

I have a simple 2 line code and i need to write the output to a file. The code is as follows:
import os,sys
print next(os.walk('/var/lib/tomcat7/webapps/'))[1]
How to do it ?

Use open() method to open file, write to write to it and close to close it as in lines below:
import os,sys
with open('myfile','w') as f:
# note that i've applied str before writing next(...)[1] to file
f.write(str(next(os.walk('/var/lib/tomcat7/webapps/'))[1]))
See Reading and Writing Files tutorial for more information of how to deal with files in python and What is the python "with" statement designed for? SO question to get better understanding of with statement.
Good Luck !

In Python 3 you can use the file parameter to the print() function:
import os
with open('outfile', 'w') as outfile:
print(next(os.walk('/var/lib/tomcat7/webapps/'))[1], file=outfile)
which saves you the bother of converting to a string, and also adds a new line after the output.
The same works in Python 2 if you add this import at the top of your python file:
from __future__ import print_function
Also in Python 2 you can use the "print chevron" syntax (that is if you do not add the above import):
with open('outfile', 'w') as outfile:
print >>outfile, next(os.walk('/var/lib/tomcat7/webapps/'))[1]
Using print >> also adds a new line at the end of each print.
In either Python version you can use file.write():
with open('outfile', 'w') as outfile:
outfile.write('{!r}\n'.format(next(os.walk('/var/lib/tomcat7/webapps/'))[1]))
which requires you to explicitly convert to a string and explicitly add a new line.
I think the first option is best.

Related

TypeError when write a dictionary to csv file [duplicate]

I have a very simple python script that should scan a text file, which contains lines formatted as id='value' and put them into a dict. the python module is called chval.py and the input file is in.txt. here's the code:
import os,sys
from os import *
from sys import *
vals = {}
f = open(sys.argv[1], 'r')
for line in val_f:
t = line.split('=')
t[1].strip('\'')
vals.append(t[0], t[1])
print vals
f.close()
when i try to run it i get:
Traceback (most recent call last):
File "chval.py", line 9, in ?
f = open(sys.argv[1], 'r') TypeError: an integer is required
I'm using python 2.4... because i've been challenged to not use anything newer, is there something about open() that I don't know about? Why does it want an integer?
anything after that line is untested. in short: why is it giving me the error and how do i fix it?
Because you did from os import *, you are (accidenally) using os.open, which indeed requires an integer flag instead of a textual "r" or "w". Take out that line and you'll get past that error.
Don't do import * from wherever without a good reason (and there aren't many).
Your code is picking up the os.open() function instead of the built-in open() function. If you really want to use os.open(), do import os then call os.open(....). Whichever open you want to call, read the documentation about what arguments it requires.
Also of note is that starting with Python 2.6 the built-in function open() is now an alias for the io.open() function. It was even considered removing the built-in open() in Python 3 and requiring the usage of io.open, in order to avoid accidental namespace collisions resulting from things such as "from blah import *". In Python 2.6+ you can write (and can also consider this style to be good practice):
import io
filehandle = io.open(sys.argv[1], 'r')
Providing these parameters resolved my issue:
with open('tomorrow.txt', mode='w', encoding='UTF-8', errors='strict', buffering=1) as file:
file.write(result)
From http://www.tutorialspoint.com/python/os_open.htm you could also keep your import and use
file = os.open( "foo.txt", mode )
and the mode could be :
os.O_RDONLY: open for reading only
os.O_WRONLY: open for writing only
os.O_RDWR : open for reading and writing
os.O_NONBLOCK: do not block on open
os.O_APPEND: append on each write
os.O_CREAT: create file if it does not exist
os.O_TRUNC: truncate size to 0
os.O_EXCL: error if create and file exists
os.O_SHLOCK: atomically obtain a shared lock
os.O_EXLOCK: atomically obtain an exclusive lock
os.O_DIRECT: eliminate or reduce cache effects
os.O_FSYNC : synchronous writes
os.O_NOFOLLOW: do not follow symlinks
that's because you should do:
open(sys.argv[2], "w", encoding="utf-8")
or
open(sys.argv[2], "w")
you have from os import * I also got the same error, remove that line and change it to import os and behind the os lib functions, add os.[function]

Writing general script using open('file', 'r')

I am writing a script where I first read a file using
with open('file', 'r') as file,
do some operation, and then write it to a new file using
with open('newfile', 'w') as newfile.
My question is, what do I need to change in the script to make it general for a number of files, so that I can just call the script with the file name from the terminal like python3 script.py file.ext? Also, is there a way to write the output back into the original file using this method?
One way of doing this is:
import sys
file=open(sys.argv[1], "r")
newfile=open("example.txt", "w")
content=file.read()
#do stuff to content here such as content=content.upper()
newfile.write(content)
If you inputted into the command line:
python script.py aaaaaa.txt
Then the file you set as the output would have the edited content of aaaaaa.txt
Hope this helps :)

portable way to write csv file in python 2 or python 3

On my Windows box, I usually did this in python 2 to write a csv file:
import csv
f = open("out.csv","wb")
cr = csv.writer(f,delimiter=';')
cr.writerow(["a","b","c"])
f.close()
Now that python 3 forbids writing text files as binary, that piece of code does not work anymore. That works:
import csv
f = open("out.csv","w",newline='')
cr = csv.writer(f,delimiter=';')
cr.writerow(["a","b","c"])
f.close()
Problem is: newline parameter is unknown to Python 2.
Of course, omitting the newline results in a csv file with too many \r chars, so not acceptable.
I'm currently performing a backwards compatible process to progressively migrate from python 2 to python 3.5
There are a lot of those statements in all my modules.
My solution was embedding the code in a custom module, and the custom module returns file handler + writer object. A python version check is done inside the module, which allows any module using my module to work whatever python version without too much hacking.
Is there a better way?
On Windows, I found a python 2 & 3 compliant way of doing it changing csv lineterminator option (which defaults to "\r\n" which makes one \r too many when file is open in text mode in Windows)
import csv
with open("out.csv","w") as f:
cr = csv.writer(f,delimiter=";",lineterminator="\n")
cr.writerow(["a","b","c"])
cr.writerow(["d","e","f"])
cr.writerow(["a","b","c"])
cr.writerow(["d","e","f"])
Whatever the python version, that will create a csv file without the infamous "blank lines".
The only drawback is that on Linux, this method would produce \r-free files, which is maybe not the standard (although files still opens properly in excel, no blank lines and still several lines :))
the problem persists on 3.6.2 (Just checked myself like I should have some time ago)
An alternative is to use a dictionary as arguments:
write_args = {"mode":"wb"} if bytes is str else {"mode":"w","newline":""}
(comparing bytes to str is one of the many ways to tell python 2 from python 3, in python 3 types are different, and it's very related to our current problem BTW).
Now we can pass those arguments with args unpacking:
with open("out.csv",**write_args) as f:
cr = csv.writer(f,delimiter=";")
For both reading and writing csv files, I've found no better way either — however I would encapsulate into a separate function as shown below. The advantage being that the logic is all in one place instead of duplicated if it's needed more than once.
import csv
import sys
def open_csv(filename, mode='r'):
"""Open a csv file in proper mode depending on Python verion."""
return(open(filename, mode=mode+'b') if sys.version_info[0] == 2 else
open(filename, mode=mode, newline=''))
with open_csv('out.csv', 'w') as f:
writer = csv.writer(f, delimiter=';')
writer.writerow([1, 2, 3])
writer.writerow(['a', 'b', 'c'])
The open_csv() utility could be simplified slightly by using the technique shown in #Jean-François Fabre's Dec 8, 2020 update to his answer to detect what version of Python is being used:
def open_csv(filename, mode='r'):
"""Open a csv file in proper mode depending on Python verion."""
return(open(filename, mode=mode+'b') if bytes is str else
open(filename, mode=mode, newline=''))

Python failing to read lines properly

I'm supposed to open a file, read it line per line and display the lines out.
Here's the code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import re
in_path = "../vas_output/Glyph/20140623-FLYOUT_mins_cleaned.csv"
out_path = "../vas_gender/Glyph/"
csv_read_line = open(in_path, "rb").read().split("\n")
line_number = 0
for line in csv_read_line:
line_number+=1
print str(line_number) + line
Here's the contents of the input file:
12345^67890^abcedefg
random^test^subject
this^sucks^crap
And here's the result:
this^sucks^crapjectfg
Some weird combo of all three. In addition to this, the result of line_number is missing. Printing out the result of len(csv_read_line) outputs 1, for some reason, no matter how many is in the input file. Changing the split type from \n to ^ gives the expected output, though, so I'm assuming the problem is probably with the input file.
I'm using a Mac, and did both the python code and the input file (on Sublime Text) on the Mac itself.
Am I missing something?
You seem to be splitting on "\n" which isn't necessary, and could be incorrect depending on the line terminators used in the input file. Python includes functionality to iterate over the lines of a file one at a time. The advantages are that it will worry about processing line terminators in a portable way, as well as not requiring the entire file to be held in memory at once.
Further, note that you are opening the file in binary mode (the b character in your mode string) when you actually intend to read the file as text. This can cause problems similar to the one you are experiencing.
Also, you do not close the file when you are done with it. In this case that isn't a problem, but you should get in the habit of using with blocks when possible to make sure the file gets closed at the earliest possible time.
Try this:
with open(in_path, "r") as f:
line_number = 0
for line in f:
line_number += 1
print str(line_number) + line.rstrip('\r\n')
So your example just works for me.
But then, i just copied your text into a text editor on linux, and did it that way, so any carriage returns will have been wiped out.
Try this code though:
import os
in_path = "input.txt"
with open(in_path, "rb") as inputFile:
for lineNumber, line in enumerate(inputFile):
print lineNumber, line.strip()
It's a little cleaner, and the for line in file style deals with line breaks for you in a system independent way - Python's open has universal newline support.
I'd try the following Pythonic code:
#!/usr/bin/env python
in_path = "../vas_output/Glyph/20140623-FLYOUT_mins_cleaned.csv"
out_path = "../vas_gender/Glyph/"
with open(in_path, 'rb') as f:
for i, line in enumerate(f):
print(str(i) + line)
There are several improvements that can be made here to make it more idiomatic python.
import csv
in_path = "../vas_output/Glyph/20140623-FLYOUT_mins_cleaned.csv"
out_path = "../vas_gender/Glyph/"
#Lets open the file and make sure that it closes when we unindent
with open(in_path,"rb") as input_file:
#Create a csv reader object that will parse the input for us
reader = csv.reader(input_file,delimiter="^")
#Enumerate over the rows (these will be lists of strings) and keep track of
#of the line number using python's built in enumerate function
for line_num, row in enumerate(reader):
#You can process whatever you would like here. But for now we will just
#print out what you were originally printing
print str(line_num) + "^".join(row)

Unable to extract information from Linux shell command using python

I am creating a Python script to collect data on underlying hardware from cat /proc/cpuinfo
I am trying to extract information i need. But I am having a problem. Here is the script
import os
p=os.popen ("cat /proc/cpuinfo")
string=[]
i=0
for line in p.readlines():
string.append(line.split(":"))
if(string[i][0]=='model name'):
fout = open("information.txt", "w")
fout.write("processor:")
fout.write(string[i][1])
fout.close()
i+=1
My program does not enter if loop at all why? Thanks in advance for help
There is no point to use cat at all here. Refactor it like this:
with open("/proc/cpuinfo") as f:
for line in f:
# potato potato ...
it probably does enter the loop but there might be a whitespace around "model name". You could call .strip() to remove it.
You can open /proc/cpuinfo as a file:
with open("/proc/cpuinfo") as file:
for line in file:
key, sep, value = line.partition(":")
if sep and key.strip() == "model name":
with open("information.txt", "w") as outfile:
outfile.write("processor:" + value.strip())
break
Hard to say what exactly is wrong. I could not figure that out at a glance, though on my Ubuntu 12.10 it also fails in the same way. Anyway, use the subprocess module since popen is deprecated.
subprocess.check_output(['cat', '/proc/cpuinfo']) returns a string quite successfully, at least on my system. And subprocess.check_output(['cat', '/proc/cpuinfo']).split('\n') will give you a list you may iterate through.
Also note that string[i][0]=='model name' won't work. There are tabs after splitting that line by ':'. Do not forget to call strip(): string[i][0].strip()=='model name'
Then, on Python 2.6+ (or even 2.5+, though 2.5 requires from __future__ import with_statement) it's almost always a good practice to use with for dealing with a file you need to open:
with open("information.txt", "w") as fout:
fout.write("processor:")
fout.write(string[i][1])
And finally, those saying you may just open a file and read it, are quite right. That is the best solution:
with open('/proc/cpuinfo') as f:
#Here you may read the file directly.
You could try doing it as :
for line in p.readlines():
line=line.split(":")
if(line[0]=='model name\t') :
#Do work
If you dont need the complete list string.

Categories

Resources