penatozawa penatozawa - 1 year ago 111
Bash Question

execvp() ls no such file or directory

I am writing a shell emulator where if the user types "lsh ls" I would run the command

and ignore the "lsh" that was input by the user. So I am using the readline library to get the input, and then parsing the line. Then I am using fork() and execvp() to run the ls command. However, When I type
lsh ls
I get the following output:

lsh: ls: No such file or directory

Here is my code. I think it's treating ls as a file to search, but I don't get why it is doing this.

int main(){
pid_t id;
char* line;
char **args;
line = readline("shell: > ");
if(strcmp(line,"exit") == 0){
args = parse(line);
if(strcmp(args[0],"lsh") == 0){
id = fork();
if (id == 0){
if(execvp(args[1],args) < 0){
perro("no such command");
if(id > 0){
printf("I am the parent process, id %d\n",getppid());

Here is the function which parses the line.

#define LSH_TOK_BUFSIZE 64
#define LSH_TOK_DELIM " \t\r\n\a"
char **parse(char *line){
int bufsize = LSH_TOK_BUFSIZE, position = 0;
char **tokens = malloc(bufsize * sizeof(char*));
char *token;
if (!tokens) {
fprintf(stderr, "lsh: allocation error\n");

token = strtok(line, " \n");
while (token != NULL) {
tokens[position] = token;

if (position >= bufsize) {
bufsize += LSH_TOK_BUFSIZE;
tokens = realloc(tokens, bufsize * sizeof(char*));
if (!tokens) {
fprintf(stderr, "lsh: allocation error\n");

token = strtok(NULL, LSH_TOK_DELIM);
tokens[position] = NULL;
return tokens;

Answer Source

The error message you see is coming from ls, not lsh.

You have, in effect:

char *args[] = { "lsh", "ls", 0 };

execvp(args[1], args);

This means that you attempt to execute ls, and do so successfully, but you tell ls that it is called lsh because argv[0] is set to lsh. So, when ls attempts to find a file ls in the current directory, it fails, and reports using the command name you gave it, lsh.

You could try this (the output shown was obtained on macOS Sierra):

$ cp /bin/ls xx97
$ ./xx97 23-ish
xx97: 23-ish: No such file or directory
$ rm xx97

You need to use:

execvp(argv[1], &argv[1]);

Then you'll invoke ls in an orthodox manner.