I’m stuck on Stage #YT5 and it feels like its because of bad programming practices. ive been sitting here for I think around 8 hours straight, probably more tryna figure out what to do.
I’ve tried two distinct approaches.
One, I tried to manually break down the arguments provided to the command. I’ve pasted the code below, but to explain my thought process and approach, I tried to split the arguments on the basis of single quotes, double quotes or whitespaces depending on what was given in the arguments. I made a function for the splitting and then a function for parsing based on the test cases provided but I couldn’t figure out how to generalize it so that it didn’t remove the double quotes (") for the cat command’s arguments but that it did for something like echo. And I felt really stuck and decided to scrap the whole thing by the end. I’ll paste my attempt below.
import sys, os, subprocess
def ParseArgumentsForQuotes(processedArgumentsList):
inSingleQuote = False
inDoubleQuote = False
parsedArgument = ""
parsedArgumentsList = []
afterBackSlash = False
processedArgumentsList = ",".join(processedArgumentsList)
if len(processedArgumentsList) == 0:
return parsedArgumentsList
for character in processedArgumentsList:
if afterBackSlash:
parsedArgument += character
afterBackSlash = False
continue
match character:
case ",":
if not inSingleQuote or not inDoubleQuote:
parsedArgumentsList.append(parsedArgument)
parsedArgument = ""
else:
parsedArgument += character
case "'":
if not inSingleQuote and not inDoubleQuote:
inSingleQuote = True
elif inSingleQuote and not inDoubleQuote:
inSingleQuote = False
elif inSingleQuote and inDoubleQuote:
continue
else:
parsedArgument += character
case '"':
if not inSingleQuote and not inDoubleQuote:
inDoubleQuote = True
elif not inSingleQuote and inDoubleQuote:
inDoubleQuote = False
elif inSingleQuote and inDoubleQuote:
continue
else:
parsedArgument += character
case " ":
if inSingleQuote or inDoubleQuote:
parsedArgument += character
else:
continue
case "\\":
afterBackSlash = True
case _:
parsedArgument += character
if (len(parsedArgument) > 0):
parsedArgumentsList.append(parsedArgument)
return parsedArgumentsList
def ProcessArguments(rawArguments):
inSingleQuote = False
inDoubleQuote = False
processedArgument = ""
processedArgumentsList = []
if len(rawArguments) == 0:
return processedArgumentsList
for i in range(len(rawArguments)):
match rawArguments[i]:
case "'":
if not inSingleQuote and not inDoubleQuote:
processedArgument += rawArguments[i]
inSingleQuote = True
elif inSingleQuote and not inDoubleQuote:
processedArgument += rawArguments[i]
inSingleQuote = False
else:
processedArgument += rawArguments[i]
case '"':
if not inDoubleQuote and not inSingleQuote:
processedArgument += rawArguments[i]
inDoubleQuote = True
elif inDoubleQuote and not inSingleQuote:
processedArgument += rawArguments[i]
inDoubleQuote = False
else:
processedArgument += rawArguments[i]
case " ":
if not inDoubleQuote and not inSingleQuote:
if i - 1 > 0 and rawArguments[i - 1] != " ":
processedArgumentsList.append(processedArgument)
processedArgument = ""
else:
continue
else:
processedArgument += rawArguments[i]
case "\\":
if i + 1 < len(rawArguments):
i = i + 1
processedArgument += rawArguments[i]
else:
continue
case _:
processedArgument += rawArguments[i]
if (len(processedArgument) != 0):
processedArgumentsList.append(processedArgument)
return processedArgumentsList
def getExecutablePath(executable):
system_path = os.environ.get('PATH')
directories = system_path.split(os.pathsep)
found = False
path = ""
for directory in directories:
if os.path.exists(directory) and executable in os.listdir(directory) and os.access(f"{directory}{os.path.sep}{executable}", os.X_OK):
found = True
path = directory + os.path.sep + executable
return found, path
return found, path
def main():
# TODO: Uncomment the code below to pass the first stage
builtinCommands = ["echo", "type", "exit", "pwd", "cd"]
while (True):
sys.stdout.write("$ ")
userInput = input()
#.find() returns -1 if it fails to find specified delimeter
rawArguments = userInput[userInput.find(" ") + 1:] if userInput.find(" ") + 1 != 0 else ""
command = userInput[:userInput.find(" ")] if userInput.find(" ") + 1 != 0 else userInput
#shlexOutput = shlex.split(userInput)
processedArgumentsList = []
processedArgumentsList = ProcessArguments(rawArguments)
parsedArgumentsList = ParseArgumentsForQuotes(processedArgumentsList)
if (command == "exit"):
break
elif (command == "echo"):
print(' '.join(parsedArgumentsList) if len(parsedArgumentsList) > 0 else "")
elif (command == "type"):
if (parsedArgumentsList[0] in builtinCommands):
print(f"{" ".join(parsedArgumentsList)} is a shell builtin")
else:
found, path = getExecutablePath(" ".join(parsedArgumentsList))
if (found):
print(f"{" ".join(parsedArgumentsList)} is {path}")
else:
print(f"{" ".join(parsedArgumentsList)}: not found")
elif (command == "pwd"):
print(os.getcwd())
elif (command == "cd"):
path = " ".join(parsedArgumentsList)
if (path == "~"):
path = os.environ.get('HOME')
if (os.path.exists(path)):
os.chdir(path)
else:
print(f"{command}: {path}: No such file or directory")
else:
found, path = getExecutablePath(command)
if (found):
subprocess.run((command + " " + " ".join(processedArgumentsList)), shell=True)
else:
print(f"{command}: command not found")
if __name__ == "__main__":
main()
Two, I tried the shlex.split() approach because this seemed to be what most people were using in their code but even this yielded an error for a test case (cat /tmp/…/_just_one_\\_67) for which it failed because it couldn’t find the directory?
import sys, os, subprocess, shlex
def getExecutablePath(executable):
system_path = os.environ.get('PATH')
directories = system_path.split(os.pathsep)
found = False
path = ""
for directory in directories:
if os.path.exists(directory) and executable in os.listdir(directory) and os.access(f"{directory}{os.path.sep}{executable}", os.X_OK):
found = True
path = directory + os.path.sep + executable
return found, path
return found, path
def main():
# TODO: Uncomment the code below to pass the first stage
builtinCommands = ["echo", "type", "exit", "pwd", "cd"]
while (True):
sys.stdout.write("$ ")
userInput = input()
try:
parsedInput = shlex.split(userInput)
except ValueError:
continue
command = parsedInput[:1]
arguments = parsedInput[1:]
if (command[0] == "exit"):
break
elif (command[0] == "echo"):
print(' '.join(arguments) if len(arguments) > 0 else "")
elif (command[0] == "type"):
if (arguments[0] in builtinCommands):
print(f"{" ".join(arguments)} is a shell builtin")
else:
found, path = getExecutablePath(" ".join(arguments))
if (found):
print(f"{" ".join(arguments)} is {path}")
else:
print(f"{" ".join(arguments)}: not found")
elif (command[0] == "pwd"):
print(os.getcwd())
elif (command[0] == "cd"):
path = " ".join(arguments)
if (path == "~"):
path = os.environ.get('HOME')
if (os.path.exists(path)):
os.chdir(path)
else:
print(f"{command[0]}: {path}: No such file or directory")
else:
found, path = getExecutablePath(command[0])
if (found):
subprocess.run((command[0] + " " + " ".join(arguments)), shell=True)
else:
print(f"{command[0]}: command not found")
if __name__ == "__main__":
main()
This is probably a really simple issue and I’ve just stared at it too long but any advice or guidance would be super appreciated.