Thread: Unix Command Interpreter Help

  1. #1
    Registered User
    Join Date
    Sep 2008
    Posts
    6

    Unix Command Interpreter Help

    I'm having to write a command interpreter and am stuck on one single part. I can get it to execute, and execute in the background as well. My problem is that when it executes a command in the background it does as it should except return the command prompt at the end. It'll let you input the next command, but it's just a blank line.
    I.E. it should look like this:
    myshell> ls &
    myshell> hw1.aux hw1.log hw1.tex hw2.dvi hw2.ps hw3.tex
    hw1.dvi hw1.ps hw2.aux hw2.log hw2.tex
    myshell>
    But looks like this:
    myshell> ls &
    myshell> hw1.aux hw1.log hw1.tex hw2.dvi hw2.ps hw3.tex
    hw1.dvi hw1.ps hw2.aux hw2.log hw2.tex

    Any suggestions would be appreciated.
    Code:
            const char *bg="&\n";
            fgets(argbuf, ARGLEN, stdin);
            result=strtok(argbuf, " ");
            while(strcmp(result, exits)!=0 && strcmp(result,quit)!=0){
                    background="no";
    
                    while(result != NULL){
                            if(strcmp(result, bg)==0){
                                    background="yes";
                            }
                            else{
                                    arglist[numargs++]=makestring(result);
                            }
                            result=strtok(NULL, " ");
                    }
                    if ( numargs > 0 ){             /* any args?    */
                            arglist[numargs]=NULL;  /* close list   */
                            pid_t     id;                 /* of child     */
                            id=fork();
                            if(id==0){
                                    execvp(arglist[0], arglist);
                                    perror("execvp failed");
                            }
                            else if(id<0){
                                    perror("fork failed");
                            }
                            else{
                                    if(background=="no"){
                                            waitpid(id,NULL,0);
                                    }
                            }
    
                            numargs = 0;            /* and reset    */
                    }
    
                    printf("myshell> ");
                    fgets(argbuf, ARGLEN, stdin);
                    result=strtok(argbuf, " ");
    
            }
    
    
            return 0;
    }

  2. #2
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Chappell Hill, Texas
    Posts
    2,332
    Quote Originally Posted by ashford74 View Post
    I'm having to write a command interpreter and am stuck on one single part. I can get it to execute, and execute in the background as well. My problem is that when it executes a command in the background it does as it should except return the command prompt at the end. It'll let you input the next command, but it's just a blank line.
    I.E. it should look like this:
    myshell> ls &
    myshell> hw1.aux hw1.log hw1.tex hw2.dvi hw2.ps hw3.tex
    hw1.dvi hw1.ps hw2.aux hw2.log hw2.tex
    myshell>
    But looks like this:
    myshell> ls &
    myshell> hw1.aux hw1.log hw1.tex hw2.dvi hw2.ps hw3.tex
    hw1.dvi hw1.ps hw2.aux hw2.log hw2.tex
    Hummm. Looks the same to me. What am I missing?
    Mainframe assembler programmer by trade. C coder when I can.

  3. #3
    Registered User
    Join Date
    Sep 2008
    Posts
    6
    The first one has another myshell> prompt, the bottom one does not, that space there is what I'm getting as output. So a better example for the second one would be:
    myshell> ls &
    myshell> hw1.aux hw1.log hw1.tex hw2.dvi hw2.ps hw3.tex
    hw1.dvi hw1.ps hw2.aux hw2.log hw2.tex
    <blank line>
    I need that blank line to be another myshell> prompt

  4. #4
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Chappell Hill, Texas
    Posts
    2,332
    So, there must be an extra newline character in the output line of the output above the blank line.
    Mainframe assembler programmer by trade. C coder when I can.

  5. #5
    Registered User
    Join Date
    Sep 2008
    Posts
    6
    Ok, sorry for the confusion:
    The correct output will have another myshell> prompt like this:
    myshell> ls &
    myshell> hw1.aux hw1.log hw1.tex hw2.dvi hw2.ps hw3.tex
    hw1.dvi hw1.ps hw2.aux hw2.log hw2.tex
    myshell>
    My output, instead of giving me that third myshell is giving me this
    myshell> ls &
    myshell> hw1.aux hw1.log hw1.tex hw2.dvi hw2.ps hw3.tex
    hw1.dvi hw1.ps hw2.aux hw2.log hw2.tex

    Where the space is just a blank line, instead of a myshell> output. So basically, when the background process gets done, I need it to prompt another myshell> output.

  6. #6
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Well, I might have a theory, but tell me first, what happens if you do the same without executing in the background??

  7. #7
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    I'm not sure I fully understand the logic of what you've posted (although using const char * in place of boolean seems like a nice touch), but it would seem that you would need to print a prompt twice in case of a background operation: once immediately after they type it, and once after the process finishes. I don't see that happening here.

  8. #8
    Registered User
    Join Date
    Sep 2008
    Posts
    6
    C_ntua: If I run it without executing in the background it runs exactly like it should.

    tabstop:I think I get what you are saying and might try that.

  9. #9
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by tabstop View Post
    I'm not sure I fully understand the logic of what you've posted (although using const char * in place of boolean seems like a nice touch), but it would seem that you would need to print a prompt twice in case of a background operation: once immediately after they type it, and once after the process finishes. I don't see that happening here.
    "nice touch" or relying on the compiler to merge constant strings together. The compiler may choose for some reason to NOT do that, and then this line doesn't work:
    Code:
                                    if(background=="no"){
                                            waitpid(id,NULL,0);
                                    }
    There is absolutely no guarantee in the standard that a compiler WILL merge multiple strings with the same content. You could use strcmp(), but that's quite a heavy operation comparing to just using an integral type (such as int or bool).

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  10. #10
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    So the how it should is:
    myshell> ls &
    hw1.aux hw1.log hw1.tex hw2.dvi hw2.ps hw3.tex
    hw1.dvi hw1.ps hw2.aux hw2.log hw2.tex
    myshell>
    ?

    or

    myshell> ls &
    myshell> hw1.aux hw1.log hw1.tex hw2.dvi hw2.ps hw3.tex
    hw1.dvi hw1.ps hw2.aux hw2.log hw2.tex
    myshell>

    I am asking because I think it prints ONCE myshell>, take the command, then prints again myshell> and waits for the next command. In that case what I think happens is that it prints myshell>, then the child executes the command, but before it prints the result the parent continuing its execution prints myshell>. Thus, there is a lack of syncrhonization. That is why I asked. Try printing mysehll> inside the if (id ==0) and see what happens....

  11. #11
    Registered User
    Join Date
    Sep 2008
    Posts
    6
    If I print inside if(id==0) it never gets printed out.
    The way it should print out is:
    myshell> ls &
    hw1.aux hw1.log hw1.tex hw2.dvi hw2.ps hw3.tex
    hw1.dvi hw1.ps hw2.aux hw2.log hw2.tex
    myshell> (the cursor is waiting here for next input)
    what I get is
    myshell> ls &
    hw1.aux hw1.log hw1.tex hw2.dvi hw2.ps hw3.tex
    hw1.dvi hw1.ps hw2.aux hw2.log hw2.tex
    (cursor waiting here for next input)

  12. #12
    Registered User
    Join Date
    Sep 2008
    Posts
    6
    Ok made a little progress. Just messing around, it seems after it runs the process in the background it stops on the line where it is using the fgets function. Everything before this gets printed out before it shows the output. So if I were to have it print "I'm Here" before this line, the output would look like:
    myshell> ls &
    I'm Here hw1.aux hw1.log hw1.tex hw2.dvi hw2.ps hw3.tex
    hw1.dvi hw1.ps hw2.aux hw2.log hw2.tex
    <cursor waiting for input>

    Even if I were to type "I'm Here" twice, it would just put it in the same spot. I don't know if I'm talking clearly enough, but does anyone have any more ideas?

  13. #13
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    And exactly what else do you expect it to do? It behaves exactly like I expect it to - it continues to run the main task until you run out of things to do (writing to the console and then waiting for input). If you QUICKLY typed something in, then I expect it would actually continue with that command.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  14. #14
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    The only way you can get what you want is to print myshell> after the child executes its command. This should print something, don't know why it doesn't work:
    Code:
    if (id==0) {
       printf("myshell>");
       execvp(...);
       perror(...);
    }
    If not dunno. Create a second child that waits for the first to finish and print myshell> ?
    In any case the result isn't wrong. You don't synchronize the child and the parent process in any way. And the point is not to synchronize them. Check it out on the UNIX shell and see what you get.

    Or add a usleep(...) to get your desired result!

  15. #15
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by C_ntua View Post
    The only way you can get what you want is to print myshell> after the child executes its command. This should print something, don't know why it doesn't work:
    Code:
    if (id==0) {
       printf("myshell>");
       execvp(...);
       perror(...);
    }
    If not dunno. Create a second child that waits for the first to finish and print myshell> ?
    In any case the result isn't wrong. You don't synchronize the child and the parent process in any way. And the point is not to synchronize them. Check it out on the UNIX shell and see what you get.

    Or add a usleep(...) to get your desired result!
    "Not doing anything about it" seems like the right thing to do - adding sleep to synchronize processes is a very bad practice indeed.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. How to program in unix
    By Cpro in forum Linux Programming
    Replies: 21
    Last Post: 02-12-2008, 10:54 AM
  2. Setting up a Unix box
    By @nthony in forum Tech Board
    Replies: 6
    Last Post: 07-22-2007, 10:22 PM
  3. UNIX (Linux, BSD, etc) Programming :: UNIX
    By kuphryn in forum Linux Programming
    Replies: 6
    Last Post: 04-01-2004, 08:44 PM
  4. Unix Sockets
    By prvindia in forum Linux Programming
    Replies: 5
    Last Post: 03-11-2003, 09:16 AM
  5. About Unix Programming - Making a career desision
    By null in forum C Programming
    Replies: 0
    Last Post: 10-14-2001, 07:37 AM