Home > Back-end >  How to use second token from strtok()?
How to use second token from strtok()?

Time:10-12

I am struggling with taking trying to use tokens from strtok as an input.

I want to be able to input "cd .." and have the first token be checked if it falls into the if-else condition and if it does use the second token as a parameter for chdir().

At the else-if statement, it currently ignores the code underneath. So I am unable to use chdir().

Example input: cd ..

This is what I have tried so far.

int main(){


    char input[256];
    while(1) {
        fgets(input, 256, stdin);
        char * token = strtok(input, " ");
        while (token!= NULL){
            if (strncmp(token, "exit", 4) == 0){
                exit(1);
            }
            else if (strncmp(token, "cd", 2) == 0) {
                token = strtok(NULL, " ");
                chdir(token);
            }
            else{
                printf("Command not found.\n");
                break;
            }
        }
    }
}

How would I be able to use the second token from strtok()? Any recommendations on where to go from here?

CodePudding user response:

I replaced chdir() with a printf() as the parent process will retain it's own current working directory. This way you can see it working.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    char input[] = "cd ..\n";
    char *command = strtok(input, "\n ");
    if(!strcmp(command, "cd")) {
        char *path = strtok(NULL, "\n ");
        if(!path) path = getenv("HOME");
        printf("cd %s\n", path);
    } else if(!strcmp(command, "exit"))
        return 1;
    else {
        printf("Command not found.\n");
        return 0;
    }
}

and the output is:

cd ..

You used fgets() in your original code, which will likely return the string with a trailing newline. You can remove it (see @SupportUkraine's answer), or as I did above treat it as just another delimiter.

If you don't want to use $HOME, you can use Get home directory in Linux.

You might want to use getopt() to parse a command line like this. It will make it easier if you want any of your commands to have options.

CodePudding user response:

Here's an illustration of how one might "dissect" a "command line".

#include <stdio.h>
#include <string.h>

int main() {
    char buf[ 256 ];

    strcpy( buf, "./a.out foo bar foobar barfoo\n" ); // simulate fgets()

    int ac = 0;
    char *av[ 32 ]; // Or make it dynamic (a minor challenge)
    for( char *cp = buf; ( cp = av[ ac ] = strtok( cp, " \n" ) ) != NULL; cp = NULL, ac   )
         ;

    for( int i = 0; i < ac; i   )
        printf( "%d: %s\n", i, av[i] );
    printf( "And on the end of the array: X\n", av[ac] );

    return 0;
}
0: ./a.out
1: foo
2: bar
3: foobar
4: barfoo
And on the end of the array: 00000000

Although daunting to some, that single, long-ish for() loop, with its single invocation of strtok() assigns NULL to the last element of the array (just like the big boys do with argc/argv[].)

Do one thing at a time. Don't mix-and-match by each item in your 'decoding' to do the work of fetching its own parameters.

CodePudding user response:

To me it seems that your problem is that

fgets(input, 256, stdin);

will (normally) give you a string input that has a trailing newline. In other words: If the user types "cd .." and press ENTER then the input is "cd ..\n" which leads to the tokens "cd" and "..\n". The second token is not what you want as argument for chdir.

In general the best solution is to remove that trailing newline just after fgets.

This Removing trailing newline character from fgets() input propose a solution which is very popular on SO:

fgets(input, 256, stdin);
input[strcspn(input, "\n")] = 0;  // Remove trailing newline if present

I prefer

fgets(input, 256, stdin);
size_t len = strlen(input);
if (len > 0 && input[len-1] == '\n') input[len-1] = '\0'; // Remove trailing newline if present

but that's a "matter of taste".

BTW: Once you have done this, you can stop using strncmp and instead use strcmp for an exact match. By doing that input like "exitxxx" will no longer be the same as "exit"

  •  Tags:  
  • c
  • Related