# Help needed for #YT5

**URL:** https://forum.codecrafters.io/t/help-needed-for-yt5/16182
**Category:** Challenges
**Tags:** challenge:shell
**Created:** [June 25, 2026, 4:21pm UTC](https://forum.codecrafters.io/t/help-needed-for-yt5/16182 "2026-06-25T16:21:55Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![HadiSaleemi666](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/hadisaleemi666/32/26929_2.png) [@HadiSaleemi666](https://forum.codecrafters.io/u/HadiSaleemi666)
#### Post date: [June 25, 2026, 4:21pm UTC](https://forum.codecrafters.io/t/help-needed-for-yt5/16182/1 "2026-06-25T16:21:55Z")

</div>

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.

```auto
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?

```python
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.

---

<div class="post-metadata">

### Author: ![andy1li](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/andy1li/32/10_2.png) [@andy1li](https://forum.codecrafters.io/u/andy1li)
#### Post date: [June 25, 2026, 5:10pm UTC](https://forum.codecrafters.io/t/help-needed-for-yt5/16182/3 "2026-06-25T17:10:22Z")

</div>

Hey @HadiSaleemi666, using `shell=True` sorta defeats the purpose of building your own shell. It also causes escaping to be processed a second time, which is why this stage gets tricky.

> subprocess.run((command + " " + " ".join(processedArgumentsList)), `shell=True`)

Try passing the executable and arguments directly as a list:

> subprocess.run([command[0]] + arguments, executable=path)

Let me know if you’re still stuck after trying that.

---

<div class="post-metadata">

### Author: ![HadiSaleemi666](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/hadisaleemi666/32/26929_2.png) [@HadiSaleemi666](https://forum.codecrafters.io/u/HadiSaleemi666)
#### Post date: [June 26, 2026, 4:33am UTC](https://forum.codecrafters.io/t/help-needed-for-yt5/16182/4 "2026-06-26T04:33:29Z")

</div>

That did just solve the issue but I don’t understand why? I’m going to try figuring that out but an explanation would be appreciated! If you can!

---

<div class="post-metadata">

### Author: ![andy1li](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/andy1li/32/10_2.png) [@andy1li](https://forum.codecrafters.io/u/andy1li)
#### Post date: [June 26, 2026, 5:26pm UTC](https://forum.codecrafters.io/t/help-needed-for-yt5/16182/5 "2026-06-26T17:26:03Z")

</div>

@HadiSaleemi666 When you use `subprocess.run(..., shell=True)` and join the arguments back into a string, the shell=True parses them **again**.

For example, suppose the argument you want to pass is:

```auto
hello\ world

```

If you pass it to `shell=True`, the shell interprets the `\ `as an escape, so the program receives:

```auto
hello world

```

instead of the literal `hello\ world`.

---

<div class="post-metadata">

### Author: ![system](https://canada1.discourse-cdn.com/flex003/uploads/codecrafters/original/3X/7/0/700657133935c15703e22c7c8870394f6e6dc27d.svg) [@system](https://forum.codecrafters.io/u/system)
#### Post date: [July 1, 2026, 5:26pm UTC](https://forum.codecrafters.io/t/help-needed-for-yt5/16182/6 "2026-07-01T17:26:54Z")

</div>

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.
