본문 바로가기
TIL/OS & Linux

MIT 6.828 - 1. Lab 01: Xv6 and Unix utilities - xargs 코드 및 해석

by 왁왁s 2022. 11. 5.

MIT 6.828 - 1. Lab 01: Xv6 and Unix utilities - xargs

 

 

문제 (Problems)

xargs (moderate)

Write a simple version of the UNIX xargs program: its arguments describe a command to run, it reads lines from the standard input, and it runs the command for each line, appending the line to the command's arguments. Your solution should be in the file user/xargs.c.

The following example illustrates xarg's behavior:

    $ echo hello too | xargs echo bye
    bye hello too
    $
  

Note that the command here is "echo bye" and the additional arguments are "hello too", making the command "echo bye hello too", which outputs "bye hello too".

Please note that xargs on UNIX makes an optimization where it will feed more than argument to the command at a time. We don't expect you to make this optimization. To make xargs on UNIX behave the way we want it to for this lab, please run it with the -n option set to 1. For instance

    $ (echo 1 ; echo 2) | xargs -n 1 echo
    1
    2
    $

Some hints:

  • Use fork and exec to invoke the command on each line of input. Use wait in the parent to wait for the child to complete the command.
  • To read individual lines of input, read a character at a time until a newline ('\n') appears.
  • kernel/param.h declares MAXARG, which may be useful if you need to declare an argv array.
  • Add the program to UPROGS in Makefile.
  • Changes to the file system persist across runs of qemu; to get a clean file system run make clean and then make qemu.

xargs, find, and grep combine well:

  $ find . b | xargs grep hello

will run "grep hello" on each file named b in the directories below ".".

To test your solution for xargs, run the shell script xargstest.sh. Your solution is correct if it produces the following output:

  $ make qemu
  ...
  init: starting sh
  $ sh < xargstest.sh
  $ $ $ $ $ $ hello
  hello
  hello
  $ $

You may have to go back and fix bugs in your find program. The output has many $ because the xv6 shell doesn't realize it is processing commands from a file instead of from the console, and prints a $ for each command in the file.

 


 

코드(Code) - xargs.c 파일

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/param.h" //Use for MAXARG

#define MAX_LEN 32

int main(int argc, char *argv[]) 
{
	char *command = "echo"; //command
	char *param[MAXARG]; //xargs after parameter
	char buf[MAX_LEN * MAXARG] = {0}; //argument
	char *p; //argument
	int paramCnt = 0; //paramter number
	int paramIdx; //parameter index
	int paramLen; //parameter length

	int i; //temporary
	char ch; //temporary
	int res; //read length

	if(argc > 1) {
		command = argv[1];
		for(i = 1; i < argc; ++i) {
			param[paramCnt++] = argv[i];
		}
	}
	else {
		param[paramCnt++] = command; //echo parameter
	}

	paramIdx = paramCnt;
	p = buf;
	paramLen = 0;
	
	while(1) {
		res = read(0, p, 1);
		ch = *p;

		if (res != 0 && ch != '\n' && ch != ' ') {
			++paramLen;
			++p;
			continue;
		}
		param[paramIdx++] = p - paramLen;
		paramLen = 0;

		*p = 0;
		++p;

		if (paramIdx == MAXARG && ch == ' ') {
			while ((res = read(0, &ch, 1)) != 0) {
				if (ch == '\n') {
					break;
				}
			}
		}
		if (ch != ' ') {
			if(fork() == 0) {
				exec(command, param);
				exit();
			}
			else {
				wait();
		
				paramIdx = paramCnt;
				p = buf;
			}
		}
		if (res == 0) {
			break;
		}
	}
	exit();
	
}

 


 

로직(logic) 설명

문제 hints에 알게 된, 받은 매개변수의 최댓값을 알 수 있는 MAXARG를 사용하기 위해 “kernel/param.h”를 선언한다. 변수를 여러 개 생성을 하는데 write 한 값을 화면에 출력하기 위한 “echo” command를 미리 저장해 놓는다. 또한 매개변에 대한 정보를 저장하는 변수들을 선언한다. 매개변수 정보로는 매개변수 일련번호, 길이, 개수, 값 등의 정보를 사용한다.

 

전체적인 코드의 로직은 표준 입력 stdin을 통해 read( )로 데이터를 읽어오고 xargs에 전달된 프로그램 이름과 추가 인수들을 저장하는데, 이때 띄어쓰기와 \n와 같은 개행문자를 조건으로 사용해 입력받은 매개변수를 나눈다. argc > 1 보다 큰 경우 사용자로부터 여러 개의 데이터를 입력 받은 경우이다. echo와 같은 명령어가 입력된 argv[1]를 command로 따로 빼고, param 배열에 인수를 늘려가며 매개변수들을 넣는다. argc가 1보다 작은 경우는 echo 만 param 배열에 넣는다.

 

무한 루프를 돌면서 매개변수로 입력 받은 값들의 문자 하나씩 읽는다. 만약 한 줄의 문자를 읽는 경우와 빈칸이나 \n와 같은 개행문자를 읽는 경우로 조건문을 나눈다. 또한 입력받은 매개변수를 읽는 과정 중 paramIdx MAXARG가 초과하는 경우와 빈칸인 경우를 조건식으로 두고 사용자로부터 입력을 기다리도록 while문 사용한다. 여기서 if(ch != ‘ ‘), 빈칸이 아니라면 fork( )를 통해 자식 프로세스를 생성하고, exec(command, param)을 주어 자식 프로세스는 param을 매개변수로 command 명령을 수행한다. 부모 프로세스는 자식 프로세스가 해당 임무를 수행할 때까지 wait( )를 한다.

 


구현 결과(Result)

 

댓글