Как выполнить процесс в фоновом режиме в пользовательской оболочке?

#c #shell #process

#c #оболочка #процесс

Вопрос:

У меня есть это упражнение:

 /* 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(amp;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(amp;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', ''};

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' amp;amp; count < MAXBUF) {
      inpbuf[count] = '';
      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 lungan");
      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 'amp;':
      type = AMPERSAND; break;
    default:
      type = ARG;
      /* copia gli altri caratteri del simbolo */
      while(inarg(*ptr))
        *tok   = *ptr  ;
  }

  /* aggiunge  al fondo */

  *tok   = '';
  return(type);

}

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

   for (wrk = special; *wrk != ''; 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 */

 

Я должен реализовать фоновое выполнение (amp;), но я понятия не имею, как это сделать…
Я пытался использовать wait при выполнении на переднем плане и без него при выполнении в фоновом режиме, но приглашение и вывод команды находились в одной строке, а «курсор» находился на новой строке.
Можно получить этот результат:

Command> ls amp;

// вывод

Команда> // курсор здесь

вместо:

Command> ls amp;

Command> // вывод

// курсор здесь

?

Комментарии:

1. Весь смысл запуска процесса в фоновом режиме заключается в том, что он выполняется, в то время как оболочка продолжает выполнять больше работы. Таким образом, по определению, если фоновая команда производит вывод, она будет смешана с выводами оболочки (и других команд). Вот почему фоновые процессы обычно всегда перенаправляют свои stdin / stdout / stderr.

Ответ №1:

Возможно ли получить этот результат

К сожалению, это не так. Даже когда вы запускаете программу на переднем плане, ваш курсор находится в конце вывода в терминале. Оболочка выводит эту полную строку запроса, когда программа завершается, чтобы вы знали, что у вас снова есть контроль над оболочкой. Этого не происходит с фоновым выводом, потому что вы по своей сути всегда контролируете оболочку, поэтому не имеет смысла произвольно отображать строку запроса.

Кроме того, представьте, что вы запускаете несколько фоновых процессов: вы бы хотели, чтобы все они вызывали появление строки запроса во время ввода чего-либо?