【问题标题】:How to execute a process in background in a custom shell?如何在自定义外壳中在后台执行进程?
【发布时间】:2020-12-09 17:58:11
【问题描述】:

我有这个练习:

/* smallsh.c */

#include "smallsh.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

char *prompt = "Scrivere un comando>";

void procline(void)     /* tratta una riga di input */
{

  char *arg[MAXARG+1];  /* array di puntatori per runcommand */
  int toktype;      /* tipo del simbolo nel comando */
  int narg;     /* numero di argomenti considerati finora */
  int type; /* FOREGROUND o BACKGROUND */
    
  narg=0;

  do {

    /* mette un simbolo in arg[narg] 
       ed esegue un'azione a seconda del tipo di simbolo */
    
    switch (toktype = gettok(&arg[narg])) {
    
      case ARG:   

        /* se argomento: passa al prossimo simbolo */
        
        if (narg < MAXARG) narg++;
    break;
       

      case EOL:
      case SEMICOLON:
      case AMPERSAND:

        if(toktype == AMPERSAND) type = BACKGROUND;
        else type = FOREGROUND;
      
         /* se fine riga o ';' esegue il comando ora contenuto in arg,
     mettendo NULL per indicare la fine degli argomenti: 
         serve a execvp */

        if (narg != 0) {
          arg[narg] = NULL;
          runcommand(arg, type);
        }
      
    /* se non fine riga (descrizione comando finisce con ';')
           bisogna ricominciare a riempire arg dall'indice 0 */

        if (toktype != EOL)  narg = 0; 

        break;
     }
  }

  while (toktype != EOL);  /* fine riga, procline finita */

}

void runcommand(char **cline, int type) /* esegue un comando */
{
  pid_t pid;
  int exitstat,ret;

  pid = fork();
  if (pid == (pid_t) -1) {
     perror("smallsh: fork fallita");
     return;
  }

  if (pid == (pid_t) 0) {   /* processo figlio */

    /* esegue il comando il cui nome e' il primo elemento di cline,
       passando cline come vettore di argomenti */
    //if(type == 1) sleep(2);
    execvp(*cline,cline);
    perror(*cline);
    exit(1);
  }

  /* non serve "else"... ma bisogna aver capito perche' :-)  */
 
  /* qui aspetta sempre e comunque - i comandi in background 
     richiederebbero un trattamento diverso */

  if(type == 1) { //BACKGROUND
   /*DO SOMETHING*/
  }
  else { //FOREGROUND
    //PART OF THE ORIGINAL CODE
    ret = wait(&exitstat);
    if (ret == -1) perror("wait");
  }
}

int main()
{
  while(userin(prompt) != EOF) 
    procline();
  return 0;
}
/* input.c */

#include "smallsh.h"

/* buffers per la riga di input e la sua segmentazione in "tokens";
puntatori per scorrere i buffers */

static char inpbuf[MAXBUF], tokbuf[2*MAXBUF],
        *ptr, *tok;

/* array di caratteri che hanno una interpretazione "speciale" 
nei comandi */

static char special[]=
    {' ', '\t', ';', '\n', '\0'};

int userin(char *p)     /* stampa il prompt e legge una riga */
{
  int c, count;

  /* inizializzazioni per altre routines */

  ptr = inpbuf;
  tok = tokbuf;

  /* stampa il prompt */

  printf("%s ",p);

  count=0;

  while(1) {

    if ((c = getchar()) == EOF)
      return(EOF);

    /* si copia il carattere letto in inpbuf; ma se si raggiunge 
       e supera MAXBUF, non si scrive piu' in inpbuf, 
       si continua a leggere fino a newline (si veda sotto) */

    if (count < MAXBUF)
      inpbuf[count++] = c;

    /* se si legge il newline, la riga in input e' finita */

    if (c == '\n' && count < MAXBUF) {
      inpbuf[count] = '\0';
      return(count);
    }

    /*  se e' stato superato MAXBUF, quando si arriva al newline
    si avverte che la riga e' troppo lunga e si 
        va a leggere una nuova riga */

    if (c == '\n') {    /* implicito se si arriva qui: count >= MAXBUF */
      printf("riga in input troppo lunga\n");
      count = 0;
      printf("%s ",p);
    }
  }
}

int gettok(char **outptr)   /* legge un simbolo e lo mette in tokbuf */
{
  int type;

  /* si piazza *outptr in modo che punti al primo byte dove si cominicera'
     a scrivere il simbolo letto */  

  *outptr = tok;

  /* salta eventuali spazi */

  while (*ptr == ' ' || *ptr == '\t') ptr++;

  /* copia il primo carattere del simbolo */

  *tok++ = *ptr;

  /* a seconda del carattere decide il tipo di simbolo */
  
  switch(*ptr++){

    case '\n':
      type = EOL; break;
    case ';':
      type = SEMICOLON; break;
    case '&':
      type = AMPERSAND; break;
    default:
      type = ARG;
      /* copia gli altri caratteri del simbolo */
      while(inarg(*ptr))
        *tok++ = *ptr++;
  }

  /* aggiunge \0 al fondo */

  *tok++ = '\0';
  return(type);

}

int inarg(char c)   /* verifica se c non e' un carattere speciale */
{
   char *wrk;

   for (wrk = special; *wrk != '\0'; wrk++)
       if (c == *wrk) return(0);

   return(1);
}
/* smallsh.h */

#define FOREGROUND 0 
#define BACKGROUND 1 

#define MAXARG 512  /* numero massimo di argomenti */
#define MAXBUF 512  /* lunghezza massima riga di input */


int inarg(char c);      /* verifica se c non e' un carattere speciale */

int userin(char *p);        /* stampa il prompt e legge una riga */ 

int gettok(char **outptr);  /* legge un simbolo */

void procline();            /* tratta una riga di input */

void runcommand(char **cline, int type);    /* esegue un comando */

我必须实现一个后台执行 (&) 但我不知道如何... 我尝试在前台执行时使用等待,而在后台执行时不使用,但提示符和命令输出在同一行,并且“光标”在新行上。 可以得到这样的结果:
命令> ls &
//输出
Command> //光标在这里
代替:
命令> ls &
命令> //输出
//光标在这里
?

【问题讨论】:

  • 在后台运行进程的全部意义在于它在 shell 继续运行更多内容的同时运行。因此,根据定义,如果后台命令产生输出,它将与 shell(和其他命令)的输出混合。这就是为什么后台进程通常总是将其 stdin/stdout/stderr 重定向。

标签: c shell process


【解决方案1】:

有没有可能得到这个结果

不,不幸的是,它不是。即使您在前台运行程序,您的光标也位于终端输出的末尾。当程序终止时,shell 会弹出完整的提示行,让您知道您再次控制了 shell。后台输出不会发生这种情况,因为您天生就可以控制 shell,因此任意弹出提示行是没有意义的。

另外,假设您正在运行多个后台进程:您是否希望所有这些进程在您输入内容时都显示提示行?

【讨论】:

    猜你喜欢
    • 2022-10-16
    • 1970-01-01
    • 1970-01-01
    • 2015-01-18
    • 2010-12-09
    • 2018-08-05
    • 2018-10-26
    • 2013-01-28
    • 2021-11-13
    相关资源
    最近更新 更多