Python misinterpreting sys.argv[1] when called with * as filename? - python-3.x
I'm doing a task for school where i need my program to do four things:
(1) It should take in a filename as an argument and count lines, words and chars.
(2) It should accept the argument *.py and scan all the .py files in current directory for the same as in (1)
(3) It should accept the argument * and scan ALL files in current directory for the same as in (1).
(4) I should be able to call it from command line as simply filename followed by argument. Example: Filename is Hello_world.py and takes one argument. Then it should look like this:
Hello_world arg
When I call with a specific filename as in (1) it seems to be working here:
else:
a, b, c, n = counting(call)
print('There are: ' + str(a) + ' lines, ' + str(b) + ' words and ' + str(c) + ' chars in ' + n)
but not working for (2) and (3) here:
if call == '*':
import os
for fname in os.listdir(os.getcwd()):
a, b, c, n = counting(fname)
print('There are: ' + str(a) + ' lines, ' + str(b) + ' words and ' + str(c) + ' chars in ' + n)
elif call == '*.py':
import glob
for fname in glob.glob('*.py'):
a, b, c, n = counting(fname)
print('There are: ' + str(a) + ' lines, ' + str(b) + ' words and ' + str(c) + ' chars in ' + n)
I tried printing out sys.argv[1] when using * and *.py as argument and then it prints out the first file in the directory and not * or *.py. Why is python interpreting * as a filename in the directory instead of simply the string *? How do I work around this? I tried moving the imports untill it actually entered the if/elif, but that did no change.
When it comes to making the script callable as in (4) I'm clueless, but that is not my main concern at this moment.
Entire script here:
import sys
def counting(fname):
lines = words = chars = 0
f= open(fname)
for line in f:
lines += 1
words += len(line.split())
chars += len(line)
name = f.name
f.close()
return lines, words, chars, name
def main():
call = sys.argv[1]
print(sys.argv[1])
a = b = c = 0
if call == '*':
import os
for fname in os.listdir(os.getcwd()):
a, b, c, n = counting(fname)
print('There are: ' + str(a) + ' lines, ' + str(b) + ' words and ' + str(c) + ' chars in ' + n)
elif call == '*.py':
import glob
for fname in glob.glob('*.py'):
a, b, c, n = counting(fname)
print('There are: ' + str(a) + ' lines, ' + str(b) + ' words and ' + str(c) + ' chars in ' + n)
else:
a, b, c, n = counting(call)
print('There are: ' + str(a) + ' lines, ' + str(b) + ' words and ' + str(c) + ' chars in ' + n)
if __name__ == '__main__':
main()
All help greatly appreciated. Thanks in advance!
When you run a program like:
prog *
there's no guarantee that the * will make it through to the program unscathed.
In fact, many shells will explicitly doe expansion so that the * gets turned into a number of arguments (such as every file in the current directory, for example).
In fact, you have to go out of your way to prevent this, by escaping special characters so the shell won't interpret them, such as:
prog \*
But. if you want to process all the files anyway, you should probably let the shell do what it wants, then process each of the expanded arguments separately.
In Python, that would be something like:
import sys
for arg in sys.argv[1:]: # [0] is the program name.
print(arg)
Related
Line by line comparison of text files - length error
#create empty list for wbm.txt wbm_lines = [] #read the file and append each line to the empty list with open('wbm.txt') as file_to_read: for line in file_to_read: wbm_lines.append(line) i = 1 #create empty list for docu.txt docu_lines = [] #read the file and append each line to the empty list with open('docu.txt') as file_to_read: for line in file_to_read: docu_lines.append(line) if len(wbm_lines) > len(docu_lines): for line in wbm_lines: if line != docu_lines: print("Line " + str(i) + " do not match") print('wbm.txt ' + wbm_lines[i]) print('docu.txt ' + docu_lines[i]) i += 1 else: for line in docu_lines: if line != wbm_lines: try: print("Line " + str(i) + " do not match") print('wbm.txt ' + wbm_lines[i]) print('docu.txt ' + docu_lines[i]) i += 1 except: continue But I am getting an error: print('docu.txt ' + docu_lines[i]) IndexError: list index out of range The problem is that the two text files have different lengths. How can I resolve this? Ideally, I would like to print something like --- in place of the non-existent line, while printing the other line normally.
How do I split sentence on 'and'?
I am trying to split my sentence on 'and' but some of the results looks like this My code string = 'I am handling it because it is difficult and confusing' string.split('and') Results ['I am h', 'ling it because it is difficult ', ' confusing'] I am trying to get this. How do I do it? ['I am handling it because it is difficult ', ' confusing']
Try doing string.split(" and ") It will only pick the word. But if you need spaces, this function/loop will do(tested): add_spaces(x): x[0] += ' ' for i in range(1, len(x) - 1): x[i] = ' ' + x[i] x[i] += ' ' x[-1] = ' ' + x[-1]
How to get a function value without running the whole function again
I would like to save the value of the list that was inputted earlier without having to reinput it again when I call the function to save it. Preferrably without using OOP as it is currently outside of my learning module but if its inevitable then it is welcomed as well for self learning. def createQuiz(): quiz = [] for i in range(2): quiz.append(str(i+1) + ') ' + input('Please input Question ' + str(i+1) + ':\n')) for j in range(4): quiz.append(chr(97+j) + '. ' + input('Please input option ' + str(j+1) + ':\n')) quiz.append('Answer: ' + input('Please input Answer(A,B,C,D):\n')) return quiz def saveQuiz(): with open('quiz.txt', 'w') as file: for i in createQuiz(): file.write(i) file.write('\n') def menu(): userinput = int(input()) if userinput == 1: createQuiz() elif userinput == 2: saveQuiz() I am expecting for it to save the value in the list into the file, however when I run saveQuiz() it would run the whole createQuiz() asking me to re input the value again.
your line for i in createQuiz(): was calling for a new instance of quiz and had no reference to the quiz you made before. I think you meant to do this: def createQuiz(): quiz = [] for i in range(2): quiz.append(str(i+1) + ') ' + input('Please input Question ' + str(i+1) + ':\n')) for j in range(2): quiz.append(chr(97+j) + '. ' + input('Please input option ' + str(j+1) + ':\n')) quiz.append('Answer: ' + input('Please input Answer(A,B,C,D):\n')) return quiz def saveQuiz(quiz): with open('quiz.txt', 'w') as file: for i in quiz: file.write(i) file.write('\n') quiz_instance = createQuiz() saveQuiz(quiz_instance) which gave me a file 'quiz.txt' containing 1) q1 a. a b. b Answer: b 2) q2 a. a b. b Answer: a
How to fix the error "index out of range"
I have to split the string with some "" in the string I am a beginner in python, plz help me QQ With the problem that line3 shows "index out of range" windows data = input().split(',') for i in range(len(data)): for j in range(len(data[i])): if data[i][j] == '"': data[i] += "," + data[i + 1] data.pop(i + 1) if data[i + 1][j] == '"': data[i] += "," + data[i + 1] data.pop(i + 1) print(data[i]) sample input: 'str10, "str12, str13", str14, "str888,999", str56, ",123,", 5' sample output: str10 "str12, str13" str14 "str888,999" str56 ",123," 5
Your error occurs if you acces a list/string behind its data. You are removing things and access for i in range(len(data)): ... data[i] += "," + data[i + 1] If i ranges from 0 to len(data)-1 and you access data[i+1] you are outside of your data on your last i! Do not ever modify something you iterate over, that leads to desaster. Split the string yourself, by iterating it character wise and keep in mind if you are currently inside " ... " or not: data = 'str10, "str12, str13", str14, "str888,999", str56, ",123,", 5' inside = False result = [[]] for c in data: if c == ',' and not inside: result[-1] = ''.join(result[-1]) # add .strip() to get rid of spaces on begin/end result.append([]) else: if c == '"': inside = not inside result[-1].append(c) result[-1] = ''.join(result[-1]) # add .strip() to get rid of spaces on begin/end print(result) print(*result, sep = "\n") Output: ['str10', ' "str12, str13"', ' str14', ' "str888,999"', ' str56', ' ",123,"', ' 5'] str10 "str12, str13" str14 "str888,999" str56 ",123," 5 Add .strip() to the join-lines to get rid of leading/trailing spaces: result[-1] = ''.join(result[-1]).strip()
Multiplication tables will not work in my code
What is wrong with my function? I have to write a function that prints out the multiplication table for the specified number. For example: in multiTable(num) if num = 6, then the function should print:"see attached photo".. This is python by the way. Thank you in advance for the help. Here is my code: def multiTable(num): empty="" print('\t',end='') for row in range(1,num): for column in range(1,num): empty = empty + (str(row*column) +'\t') + '\n' print(empty)
Reset variable before each loop First of all you need to reset value of empty variable before each inner loop Your value should be initialized with empty string: empty = '' range loops EXCLUISVE To loop in given range use num + 1 as the ending point Fixed code def multiTable(num): # Display top line for i in range(1, num + 1): print('\t' + str(i), end='') print() # Show mutiplication table for row in range(1, num + 1): # Start by multiplier on the left empty = str(row) + '\t' for column in range(1, num + 1): empty = empty + str(row * column) + '\t' print(empty)