Conditional elif statement is not yielding the correct results - python

The elif stament should print the log files and path that were not found in a search that I conduct. However, they yield every line that is searched in a single file (a plethora of info). What am I doing wrong?
for line in fileinput.input(walk_dir(directory, (".log", ".txt"))):
result = regex.search(whitespace.sub('', line))
if result:
template = "\nLine: {0}\nFile: {1}\nString Type: {2}\n\n"
output = template.format(fileinput.filelineno(), fileinput.filename(), result.group())
print output
temp.write(output)
break
elif not result:
template = "\nLine: {0}\nString not found in File: {1}\nString Type: {2}\n\n"
output = template.format(fileinput.filelineno(), fileinput.filename(), result.group())
print output
temp.write(output)
else:
print "There are no files in the directory!!!"
Actual Code:
elif searchType =='2':
print "\nDirectory to be searched: " + directory
print "\nFile result2.log will be created in: c:\Temp_log_files."
paths = "c:\\Temp_log_files\\result2.log"
temp = file(paths, "w")
userstring = raw_input("Enter a string name to search: ")
userStrHEX = userstring.encode('hex')
userStrASCII = ''.join(str(ord(char)) for char in userstring)
regex = re.compile(r"(%s|%s|%s)" % ( re.escape( userstring ), re.escape( userStrHEX ), re.escape( userStrASCII )))
goby = raw_input("Press Enter to begin search (search ignores whitespace)!\n")
def walk_dir(directory, extensions=""):
for path, dirs, files in os.walk(directory):
for name in files:
if name.endswith(extensions):
yield os.path.join(path, name)
whitespace = re.compile(r'\s+')
for line in fileinput.input(walk_dir(directory, (".log", ".txt"))):
result = regex.search(whitespace.sub('', line))
if result:
template = "\nLine: {0}\nFile: {1}\nString Type: {2}\n\n"
output = template.format(fileinput.filelineno(), fileinput.filename(), result.group())
print output
temp.write(output)
#break
elif result not in line:
output = fileinput.filename()
print output
temp.write(output)
break
else:
print "There are no files in the directory!!!"

You're iterating over every line of every file passed to fileinput.input(...), right? And you perform the if statement for every line. If the condition is true, then you break, but if the condition is false, you don't break, but write to temp. So for every line in fileinput.input that doesn't match the condition, you write a line to temp and print output. (Actually, the above is wrong -- see edit below.)
Also, elif str(result) not in line: will have strange results -- just use else as others have suggested. If result evaluates to false in this situation, then result == None, which means that str(result) == 'None', which means that if a line contains None, then you'll have unexpected results.
Edit: Ok, actually, looking more closely at your actual code the above is wrong, strictly speaking. But the point remains -- fileinput.input() returns a FileInput object that in essence concatenates the files and iterates over every line in turn. Since in some cases you don't want to perform an action per line, but per file, you'll have to iterate over them individually. You could do this without fileinput but since that's what you're using, we'll stick with that:
for filename in walk_dir(directory, (".log", ".txt")):
for line in fileinput.input(filename):
result = regex.search(whitespace.sub('', line))
if result:
template = "\nLine: {0}\nFile: {1}\nString Type: {2}\n\n"
output = template.format(fileinput.filelineno(), fileinput.filename(), result.group())
print output
break # (assuming you only want to print the first result)
else:
ouput = fileinput.filename()
print output
temp.write(output)
break
The way this works: for every file in the list, this prints the first match in the file, or prints the filename if no match was found. You can use else with a for loop in python; the else block at the end of the loop is executed if the loop is not broken. Since no match was found, the filename is printed.
If you wanted to print out all matches in a file, you could save the matches in a list, and instead of using else, you could test the list. Simplified example:
matches = []
for line in fileinput.input(filename):
if searchline(line):
matches.append(line)
if matches:
print template.format(matches)
else:
print fileinput.filename()

Related

Program not recognizing conditional statements in for loop

I'm trying to print "None" if the input entered by the user is not found in a text file I created. It should also print if the lines if word(s) are found in the text file.
My problem right now is that it is not doing both conditionals. If I were to remove the "line not in user_pass" it would not print anything. I just want the user to be able to know if the strings entered by the user can found in the file and will print that line or "none" if it is not found.
I commented out the ones where I tried fixing my code, but no use.
My code below:
def text_search(text):
try:
filename = "words.txt"
with open(filename) as search:
print('\nWord(s) found in file: ')
for line in search:
line = line.rstrip()
if 4 > len(line):
continue
if line.lower() in text.lower():
print("\n" + line)
# elif line not in text: # the function above will not work if this conditional commented out
# print("None")
# break
# if line not in text: # None will be printed so many times and line.lower in text.lower() conditional will not work
# print("none")
except OSError:
print("ERROR: Cannot open file.")
text_search("information")
I think you need to change for line in search: to for line in search.readlines(): I don't think you're ever reading from the file... Have you tried to just print(line) and ensure your program is reading anything at all?
#EDIT
Here is how I would approach the problem:
def text_search(text):
word_found = False
filename = "words.txt"
try:
with open(filename) as file:
file_by_line = file.readlines() # returns a list
except OSError:
print("ERROR: Cannot open file.")
print(file_by_line) # lets you know you read the data correctly
for line in file_by_line:
line = line.rstrip()
if 4 > len(line):
continue
if line.lower() in text.lower():
word_found = True
print("\n" + line)
if word_found is False:
print("Could not find that word in the file")
text_search("information")
I like this approach because
It is clear where you are reading the file and assigning it to a variable
This variable is then printed, which is useful for debugging
Less stuff is in a try: clause (I like to not hide my errors, but that's not a huge deal here because you did a good job specifying OSError however, what if an OSError occured during line = line.rstrip() for some reason...you would never know!!)
If this helped I'd appreciate if you would click that green check :)
Try this:-
def find_words_in_line(words,line):
for word in words:
if(word in line):
return True;
return False;
def text_search(text,case_insensitive=True):
words = list(map(lambda x:x.strip(),text.split()));
if(case_insensitive):
text = text.lower();
try:
filename = 'words.txt'
with open(filename) as search:
found = False;
for line in search:
line = line.strip();
if(find_words_in_line(words,line)):
print(line);
found = True;
if(not found):
print(None);
except:
print('File not found');
text_search('information');
Didn't really understand your code, so making one on my own according to your requirement.

replace function not working with list items

I am trying to use the replace function to take items from a list and replace the fields below with their corresponding values, but no matter what I do, it only seems to work when it reaches the end of the range (on it's last possible value of i, it successfully replaces a substring, but before that it does not)
for i in range(len(fieldNameList)):
foo = fieldNameList[i]
bar = fieldValueList[i]
msg = msg.replace(foo, bar)
print msg
This is what I get after running that code
<<name>> <<color>> <<age>>
<<name>> <<color>> <<age>>
<<name>> <<color>> 18
I've been stuck on this for way too long. Any advice would be greatly appreciated. Thanks :)
Full code:
def writeDocument():
msgFile = raw_input("Name of file you would like to create or write to?: ")
msgFile = open(msgFile, 'w+')
msg = raw_input("\nType your message here. Indicate replaceable fields by surrounding them with \'<<>>\' Do not use spaces inside your fieldnames.\n\nYou can also create your fieldname list here. Write your first fieldname surrounded by <<>> followed by the value you'd like to assign, then repeat, separating everything by one space. Example: \"<<name>> ryan <<color>> blue\"\n\n")
msg = msg.replace(' ', '\n')
msgFile.write(msg)
msgFile.close()
print "\nDocument written successfully.\n"
def fillDocument():
msgFile = raw_input("Name of file containing the message you'd like to fill?: ")
fieldFile = raw_input("Name of file containing the fieldname list?: ")
msgFile = open(msgFile, 'r+')
fieldFile = open(fieldFile, 'r')
fieldNameList = []
fieldValueList = []
fieldLine = fieldFile.readline()
while fieldLine != '':
fieldNameList.append(fieldLine)
fieldLine = fieldFile.readline()
fieldValueList.append(fieldLine)
fieldLine = fieldFile.readline()
print fieldNameList[0]
print fieldValueList[0]
print fieldNameList[1]
print fieldValueList[1]
msg = msgFile.readline()
for i in range(len(fieldNameList)):
foo = fieldNameList[i]
bar = fieldValueList[i]
msg = msg.replace(foo, bar)
print msg
msgFile.close()
fieldFile.close()
###Program Starts#####--------------------
while True==True:
objective = input("What would you like to do?\n1. Create a new document\n2. Fill in a document with fieldnames\n")
if objective == 1:
writeDocument()
elif objective == 2:
fillDocument()
else:
print "That's not a valid choice."
Message file:
<<name>> <<color>> <<age>>
Fieldname file:
<<name>>
ryan
<<color>>
blue
<<age>>
18
Cause:
This is because all lines except the last line read from the "Fieldname" file contains "\n" characters. So when the program comes to the replacing part fieldNameList , fieldValueList and msg looks like this:
fieldNameList = ['<<name>>\n', '<<color>>\n', '<<age>>\n']
fieldValueList = ['ryan\n', 'blue\n', '18']
msg = '<<name>> <<color>> <<age>>\n'
so the replace() function actually searches for '<<name>>\n','<<color>>\n','<<age>>\n' in msg string and only <<age>> field get replaced.(You must have a "\n" at the end of msg file, otherwise it won't be replaced as well).
Solution:
use rstrip() method when reading lines to strip the newline character at the end.
fieldLine = fieldFile.readline().rstrip()

Pythonic way to traverse etc shadows

I am trying to implement a logic using python :
cat /etc/shadow | awk -F: '($2 == "" ) { print $1 " does not have a password "}'
If the above returns the output for the user i will do
passwd -l <username>
I am trying to implement the above logic using python , but i am not really sure if it is working out in that way; here is my python code:
/etc/shadow looks like
root:*:17709:0:99999:7:::
daemon:*:17709:0:99999:7:::
bin:*:17709:0:99999:7:::
sys:*:17709:0:99999:7:::
sync:*:17709:0:99999:7:::
games:*:17709:0:99999:7:::
man:*:17709:0:99999:7:::
lp:*:17709:0:99999:7:::
mail:*:17709:0:99999:7:::
news:*:17709:0:99999:7:::
uucp:*:17709:0:99999:7:::
proxy:*:17709:0:99999:7:::
www-data:*:17709:0:99999:7:::
backup:*:17709:0:99999:7:::
CODE
with open("/etc/shadow") as file:
for line in file:
line = line.rstrip()
if line[line.find(":")+1:line.find(":")]=="":
print "This is a problem"
elif line[line.find(":")+1:line.find(":")]=="*":
print line[line.find(":")+1:line.find(":")]
else:
print "All Good"
The above code returns "This is a problem" , which isn't right
You can use re to extract desired column:
import re
data = """root:*:17709:0:99999:7:::
daemon:*:17709:0:99999:7:::
bin:*:17709:0:99999:7:::
sys:*:17709:0:99999:7:::
sync:*:17709:0:99999:7:::
games:*:17709:0:99999:7:::
man:*:17709:0:99999:7:::
lp:*:17709:0:99999:7:::
mail:*:17709:0:99999:7:::
news:*:17709:0:99999:7:::
uucp:*:17709:0:99999:7:::
proxy:*:17709:0:99999:7:::
www-data:*:17709:0:99999:7:::
backup:*:17709:0:99999:7:::"""
groups = re.findall('(.*?):(.*?):(.*?):(.*?):(.*?):(.*?):(.*?):(.*?):', data)
if all(g[1].strip() for g in groups):
print('All good')
else:
print('This is a problem')
This prints:
All good
Explanation of this regex here. In the second group (g[1]), you have the shadowed password (*), or empty string.
Try it:
with open("/etc/shadow/") as ff:
for line in ff:
login_name,pwd,remainder=line.split(":",maxsplit=2)
print(login_name,pwd) # change it as you like
Just split your lines on the ":" separator and check the value at the second position (which is at index 1 of course):
data = """
root:*:17709:0:99999:7:::
daemon:*:17709:0:99999:7:::
bin:*:17709:0:99999:7:::
sys:*:17709:0:99999:7:::
sync:*:17709:0:99999:7:::
games:*:17709:0:99999:7:::
man:*:17709:0:99999:7:::
lp:*:17709:0:99999:7:::
mail:*:17709:0:99999:7:::
news:*:17709:0:99999:7:::
uucp:*:17709:0:99999:7:::
proxy:*:17709:0:99999:7:::
www-data:*:17709:0:99999:7:::
backup:*:17709:0:99999:7:::
"""
for line in data.strip().splitlines():
row = [part.strip() for part in line.split(":")]
if row[1] == "":
print("this is a problem")
elif row[1] == "*":
print row[1]
else:
print "all good"

Python Replace String in File in With clause

I am trying to replace a string in a file.
Below code is simply modifying certain substrings within the bigger string from the file. Any ideas on how I can actually replace line with current_line in the filename?
from sys import *
import os
import re
import datetime
import fileinput
script, filename = argv
userhome = os.path.expanduser('~')
username = os.path.split(userhome)[-1]
print "\n"
print "User: " + username
today = datetime.date.today().strftime("%Y/%m/%d")
time = datetime.datetime.now().strftime("%H:%M:%S")
print "Date: " + str(today)
print "Current time: " + str(time)
print "Filename: %s\n" % filename
def replace_string():
found = False
with open(filename, 'r+') as f:
for line in f:
if re.search("CVS Header", line):
print line
####################################################################################
# Below logic: #
# if length of revision number is 4 characters (e.g. 1.15) then increment by 0.01 #
# else if it is 3 characters (e.g. 1.5) then increment by 0.1 #
####################################################################################
if len(line.split("$Revision: ")[1].split()[0]) == 4:
new_line = str.replace(line, line.split("$Revision: ")[1].split()[0], str(float(line.split("$Revision: ")[1].split()[0]) + 0.01))
elif len(line.split("$Revision: ")[1].split()[0]) == 3:
new_line = str.replace(line, line.split("$Revision: ")[1].split()[0], str(float(line.split("$Revision: ")[1].split()[0]) + 0.1))
###
###
newer_line = str.replace(new_line, line.split("$Author: ")[1].split()[0], username)
newest_line = str.replace(newer_line, line.split("$Date: ")[1].split()[0], today)
current_line = str.replace(newest_line, line.split("$Date: ")[1].split()[1], time)
print current_line
found = True
if not found:
print "No CVS Header exists in %s" % filename
if __name__ == "__main__":
replace_string()
I tried adding something like..
f.write(f.replace(line, current_line))
but this just clears all the contents out of the file and leaves it blank so obviously that is incorrect.
The fileinput provides a way to edit a file in place. If you use the inplace parameter the file is moved to a backup file and standard output is directed to the input file.
import fileinput
def clause(line):
return len(line) < 5
for line in fileinput.input('file.txt', inplace=1):
if clause(line):
print '+ ' + line[:-1]
fileinput.close()
Trying to apply this idea to your example, it could be something like this:
def replace_string():
found = False
for line in fileinput.input(filename, inplace=1): # <-
if re.search("CVS Header", line):
#print line
####################################################################################
# Below logic: #
# if length of revision number is 4 characters (e.g. 1.15) then increment by 0.01 #
# else if it is 3 characters (e.g. 1.5) then increment by 0.1 #
####################################################################################
if len(line.split("$Revision: ")[1].split()[0]) == 4:
new_line = str.replace(line, line.split("$Revision: ")[1].split()[0], str(float(line.split("$Revision: ")[1].split()[0]) + 0.01))
elif len(line.split("$Revision: ")[1].split()[0]) == 3:
new_line = str.replace(line, line.split("$Revision: ")[1].split()[0], str(float(line.split("$Revision: ")[1].split()[0]) + 0.1))
###
###
newer_line = str.replace(new_line, line.split("$Author: ")[1].split()[0], username)
newest_line = str.replace(newer_line, line.split("$Date: ")[1].split()[0], today)
current_line = str.replace(newest_line, line.split("$Date: ")[1].split()[1], time)
print current_line[:-1] # <-
found = True
else:
print line[:-1] # <- keep original line otherwise
fileinput.close() # <-
if not found:
print "No CVS Header exists in %s" % filename
The solution proposed by user2040251 is the correct way, and the way used but all text editors I know. The reason is that in case of a major problem when writing the file, you keep the previous version unmodified until the new version is ready.
But of course if you want you can edit in place, if you accept the risk of completely losing the file in case of crash - it can be acceptable for a file under version control since you can always get previous commited version.
The principle is then a read before write, ensuring that you never write something that you have not still read.
At the simplest level, you load everything in memory with readlines, replace the line rewind the file the the correct position (or to the beginning) and write it back.
Edit : here is a simple implementation when all lines can be loaded in memory :
fd = open(filename, "r+")
lines = fd.readlines()
for i, line in enumerate(lines):
# test if line if the searched line
if found :
lines[i] = replacement_line
break
fd.seek(0)
fd.writelines()
It could be done even for a big file using readlines(16384) for example instead of readlines() to read by chunks of little more than 16K, and always reading one chunk before writing previous, but it is really much more complicated and anyway you should use a backup file when processing big files.
You can create another file and write the output to it. After that, you can just remove the original file and rename the new file.

No output on command line python

This is my code. when I run it, it simply exits after running. There is nothing printed. Why so ?
def checkString(filename, string):
input = file(filename) # read only will be default file permission
found = False
searchString = string
for line in input:
if searchString in line:
found = True
break
if callfunc == 'initialize':
print listdir() #this will print list of files
print "\n"
for files in listdir():
checkString(files,"hello")
if found:
print "String found"
else:
print "String not found"
input.close()
found is a local name in the function checkString(); it stays local because you don't return it.
Return the variable from the function and store the return value:
def checkString(filename, string):
input = file(filename) # read only will be default file permission
found = False
searchString = string
for line in input:
if searchString in line:
found = True
break
return found
for files in listdir():
found = checkString(files,"hello")
if found:
print "String found"
else:
print "String not found"
You need to modify to:
def checkString(filename, string):
input = file(filename) # read only will be default file permission
found = False
searchString = string
for line in input:
if searchString in line:
found = True
break
input.close()
return found
found = False
if callfunc == 'initialize':
print listdir() #this will print list of files
print "\n"
for files in listdir():
found = found or checkString(files,"hello")
if found:
print "String found"
else:
print "String not found"
This is because in your original found is only in scope within the function checkString

Categories