# Stderr redirection

**URL:** <https://forum.codecrafters.io/t/stderr-redirection/4858>\
**Category:** Challenges\
**Tags:** challenge:shell\
**Created:** [February 14, 2025, 8:38am UTC](https://forum.codecrafters.io/t/stderr-redirection/4858 "2025-02-14T08:38:04Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![BardhT](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/bardht/32/4923_2.png) [@BardhT](https://forum.codecrafters.io/u/BardhT)\
**Post date:** [February 14, 2025, 8:38am UTC](https://forum.codecrafters.io/t/stderr-redirection/4858/1 "2025-02-14T08:38:04Z")

</div>

I’m stuck on Stage #VZ4

I’ve tried commenting out all extra error messages I had initially added, but somehow when the test calls “ls” which is not a built in shell command it spits out an error message that is specific to “cd” which is built in command. It also spits the error to stdout instead of stderr which makes it fail the test.

Here are my logs:

```auto
[compile] Compilation successful.

Debug = true

[tester::#VZ4] Running tests for Stage #VZ4 (Redirection - Redirect stderr)
[tester::#VZ4] [setup] export PATH=/tmp/raspberry/apple/banana:$PATH
[tester::#VZ4] Running ./your_program.sh
[tester::#VZ4] [setup] echo -n "apple" > "/tmp/baz/apple"
[your-program] $ ls -1 nonexistent 2> /tmp/qux/foo.md
[your-program] ls: /tmp/qux/foo.md: No such file or directory
[tester::#VZ4] Expected prompt ("$ ") but received "ls: /tmp/qux/foo.md: No such file or directory"
[your-program] ls: nonexistent: No such file or directory
[your-program] $ 
[tester::#VZ4] Assertion failed.
[tester::#VZ4] Test failed

```

And here’s a snippet of my code:

```C++
    std::unordered_set<std::string> builtIn = {"echo", "exit", "type", "pwd", "cd"};
    std::unordered_set<char> escapedChars = {'\\', '$', '\"', '\n'};
    std::unordered_set<std::string> outRedirect = {">", "1>"};
    std::vector<std::string> pathDirs;
    std::string currentDir;
    int stdOut, stdError;
    bool out = false, error = false;

    std::vector<std::string> tokenizeInput(const std::string& input) {
        bool singleQuote = false, doubleQuote = false;
        std::vector<std::string> tokens;
        std::string token;

        for (size_t i = 0; i < input.size(); i++) {
            char c = input[i];
            if (c == ' ' && !singleQuote && !doubleQuote) {
                if (token == "2>") error = true;
                else if (!token.empty() && outRedirect.find(token) == outRedirect.end() && !out) tokens.push_back(token);
                else if (outRedirect.find(token) != outRedirect.end()) out = true;
                else if (out && !token.empty()) handleOutputRedirection(token); 
                else if (error && !token.empty()) handleErrorRedirection(token);
                token.clear();
            } else if (c == '\'' && !doubleQuote) {
                singleQuote = !singleQuote;
            } else if (c == '\"' && !singleQuote) {
                doubleQuote = !doubleQuote;
            } else if (c == '\\') {
                if (singleQuote) {
                    token += c;
                } else if (doubleQuote) {
                    if (i+1 < input.size() && escapedChars.find(input[i+1]) != escapedChars.end()) {
                        token += input[++i];
                    } else {
                        token += c;
                    }
                } else if (i+1 < input.size()) {
                    token += input[++i];
                }
            } else token += c;
        }

        if (!token.empty() && !out) tokens.push_back(token);
        else if (!token.empty()) handleOutputRedirection(token);

        return tokens;
    }

    void handleOutputRedirection(std::string file) {
        int fd = open(file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
        if (fd == -1) {
            // perror("open");
            return;
        }

        dup2(fd, STDOUT_FILENO);
        close(fd);
    }

    void handleErrorRedirection(std::string file) {
        int fd = open(file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
        if (fd == -1) {
            // perror("open");
            return;
        }

        dup2(fd, STDERR_FILENO);
        close(fd);
    }

    void closeErrorRedirect() {
        dup2(stdError, STDERR_FILENO);
        error = false;
    }

    void closeOutputRedirect() {
        dup2(stdOut, STDOUT_FILENO);
        out = false;
    }

```

Code for cd and external commands:

```C++
    void handleCd(const std::vector<std::string>& tokens) {
        int status = 0;
        if (tokens.size() == 1 || tokens[1][0] == '~') {
            status = chdir(getenv("HOME"));
        } else {
            status = chdir(tokens[1].c_str());
        }

        if (status == -1) {
            std::cerr << tokens[0] << ": " << tokens[1] << ": No such file or directory" << std::endl;
        } else {
            currentDir = std::filesystem::current_path();
        }
    }

    void executeExternalCommand(const std::vector<std::string>& tokens) {
        std::vector<char*> args(tokens.size() + 1);
        for(size_t i = 0; i < tokens.size(); i++) {
            args[i] = const_cast<char*>(strdup(tokens[i].c_str()));
        }
        args[tokens.size()] = nullptr;
        
        pid_t pid = fork();
        
        if (pid < 0) { 
            // perror("fork");
            return;
        } else if (pid > 0) { // Parent
            int status;
            if (waitpid(pid, &status, 0) == -1) {
                // perror("waitpid");
                return;
            }
            
            if (WIFEXITED(status) && WEXITSTATUS(status) == 127) {
                std::cerr << tokens[0] << ": command not found" << std::endl;
            } else if (WIFSIGNALED(status)) {
                // std::cout << tokens[0] << ": terminated by signal " << WTERMSIG(status) << std::endl;
            } else if (WIFEXITED(status) != 0 && WEXITSTATUS(status) != 0) {
                // std::cout << tokens[0] << ": exit status " << WEXITSTATUS(status) << std::endl;
            }
        } else if (pid == 0) { // Child    
            execvp(tokens[0].c_str(), args.data());
            // std::cerr << "Execution failed for command: " << tokens[0] << std::endl;
            // perror("execvp");
            exit(127);
        }

        for (size_t i = 0; i < tokens.size(); i++) {
            free(args[i]);
        }
    }

```

---

<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:** [February 14, 2025, 8:39am UTC](https://forum.codecrafters.io/t/stderr-redirection/4858/2 "2025-02-14T08:39:19Z")

</div>

Hi @BardhT, could you [upload your code to GitHub](https://docs.codecrafters.io/features/publish-to-github) and share the link? It will be much easier to debug if I can run it directly.

---

<div class="post-metadata">

**Author:** ![BardhT](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/bardht/32/4923_2.png) [@BardhT](https://forum.codecrafters.io/u/BardhT)\
**Post date:** [February 14, 2025, 8:41am UTC](https://forum.codecrafters.io/t/stderr-redirection/4858/4 "2025-02-14T08:41:09Z")

</div>

Link to repo: [redacted by Andy]

---

<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:** [April 23, 2025, 11:05am UTC](https://forum.codecrafters.io/t/stderr-redirection/4858/5 "2025-04-23T11:05:20Z")

</div>

@BardhT Sorry for the delayed response!

> It also spits the error to stdout instead of stderr which makes it fail the test.

Could you share more details on how you verified that? Would be helpful to pinpoint what’s going wrong.

---

<div class="post-metadata">

**Author:** ![senevoldsen](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/senevoldsen/32/6460_2.png) [@senevoldsen](https://forum.codecrafters.io/u/senevoldsen)\
**Post date:** [April 26, 2025, 7:58am UTC](https://forum.codecrafters.io/t/stderr-redirection/4858/7 "2025-04-26T07:58:10Z")

</div>

It seems to me you only “complete” tokens when they are succeeded by a space in your tokenizeInput. So, to me, it looks like, if you see `2>` that you set error to `true`. Then on your next token you would ideally match `(error && !token.empty())` and run `handleErrorRedirection(token)`.

But what happens when the input ends without a `' '` after it; do you modify the input command to always have an extra space at the end? Otherwise the, assuming no `out`put redirection, if will just add the file name to the tokens list before returning at the end. It does not seem like `handleErrorRedirection` would trigger.

This might explain the error you get too: instead of redirecting to `/tmp/qux/foo.md`, you are just passing it as a argument I guess, and since the file doesn’t exist you are told: `"ls: /tmp/qux/foo.md: No such file or directory"`.

---

<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:** [May 4, 2025, 7:38pm UTC](https://forum.codecrafters.io/t/stderr-redirection/4858/8 "2025-05-04T19:38:39Z")

</div>

Closing this thread due to inactivity. If you still need assistance, feel free to reopen or start a new discussion!

---

<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:** [May 9, 2025, 7:39pm UTC](https://forum.codecrafters.io/t/stderr-redirection/4858/9 "2025-05-09T19:39:34Z")

</div>

Closed on May 9, 2025, 7:39pm UTC

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