#JV1 ls: >: No such file or directory

I’m stuck on Stage #JV1

I’ve tried to separate the full command into 2 parts : the text (toRedirect) and the file (redirectionLocation) then used ofstream to handle the > operator logic

Here are my logs:

[tester::#JV1] Running tests for Stage #JV1 (Redirection - Redirect stdout)
[tester::#JV1] [setup] export PATH=/tmp/orange/grape/pineapple:$PATH
[tester::#JV1] Running ./your_program.sh
[tester::#JV1] [setup] echo "banana" > "/tmp/owl/banana"
[tester::#JV1] [setup] echo "grape" > "/tmp/owl/grape"
[tester::#JV1] [setup] echo "pear" > "/tmp/owl/pear"
[your-program] $ ls -1 /tmp/owl > /tmp/ant/bee.md
[your-program] ls: /tmp/ant/bee.md: No such file or directory
[tester::#JV1] ^ Expected prompt ("$ ") but received "ls: /tmp/ant/bee.md: No such file or directory"
[your-program] ls: >: No such file or directory
[your-program] banana
[your-program] grape
[your-program] pear
[your-program] $ 
[tester::#JV1] Test failed

And here’s a snippet of my code:

/// Redirection
void redirect_output(const std::string& fileName, const std::string& text) {
	std::ofstream outFile(fileName, std::ios::out);

	if (outFile.is_open()) {
		outFile << text << "\n";
		outFile.close();
	}
	else {
		std::cerr << "shell: " << fileName << ": " << std::strerror(errno) << std::endl;
	}
}

Here is the echo command logic (inside main) :

// echo command
else if (command.find("echo ") == 0) {
 std::string toPrint = command.substr(5);

 size_t redirPos = toPrint.find('>');

 if (redirPos != std::string::npos) {
  // what to redirect
  std::string toRedirect = toPrint.substr(0, redirPos);
  // where to redirect
  std::string redirectLocation = toPrint.substr(redirPos + 1);

  // Clean up leading/trailing spaces from the text
  if (!toRedirect.empty() && toRedirect.back() == ' ') {
	  toRedirect.pop_back();
  }

  // Remove leading spaces from the filename path
  size_t firstNonSpace = redirectLocation.find_first_not_of(" ");
  if (firstNonSpace != std::string::npos) {
	  redirectLocation = redirectLocation.substr(firstNonSpace);
  }

  redirect_output(redirectLocation, toRedirect);
 }
 else {
  std::vector<std::string> arguments = handlQuotes(toPrint);
  for (size_t i = 0; i < arguments.size(); i++) {
	  std::cout << arguments[i];
	  if (i < arguments.size() - 1) {
		  std::cout << " ";
	  }
  }
  std::cout << "\n";
 }		  
}

Hey @VOIDPACKET-VP, could you upload your code to GitHub and share the link? It will be much easier to debug if I can run it directly.

Yeah sure, here is the link GitHub - VOIDPACKET-VP/VOIDPACKET-VP-codecrafters-shell-cpp: My progress on the shell project · GitHub

And thank you for taking the time with this

@VOIDPACKET-VP There might be a few issues at play, but here’s the first one I noticed:

After calling exec, your shell process is replaced by the target program. At that point, your shell is no longer running, so it can’t tell the program to “write to this file.”

Instead, you need to redirect stdout before calling exec, so that anything the program writes to stdout automatically goes to the file.

In the child process (after fork):

  1. open the output file.
  2. dup2(fd, STDOUT_FILENO) to redirect stdout to the file.
  3. close(fd), since stdout now refers to the file.
  4. exec the target program.

I will take a loot at that and get back to you. Thanks

Solved it, this has to be the hardest challenge i faced so far, i don’t think it should be set to medium, hard suits it i think, or it’s just me maybe. Thank you @andy1li