셸 을 이해 하 는 좋 은 방법 배우 기 - 자신의 셸 을 만 드 는 2

셸 스 크 립 트 의 가장 간단 한 형식 은 명령 의 나열 입 니 다. 셸 은 해석 기 를 충당 하고 마지막 명령 이나 종료 명령 을 만 날 때 까지 하나씩 실행 합 니 다.그러나 이것 은 아주 간단 한 일 을 할 수 밖 에 없다. 매번 명령 을 한 번 씩 두 드 려 야 하 는 시간 을 줄 이 고 더욱 잡다 한 기능 을 완성 하려 면 이런 것들 을 더 해 야 한다.
1. 제어
앞의 조건 이 만족 한 후에 무엇 을 합 니까?불만족
2. 변수
c = a + b 는 한 가지 형식 으로 다른 형식 을 대표 하 는데 바로 변수 입 니 다.형식 이 다 르 기 때문에 변 하지 않 는 것 으로 다른 변 화 를 나 타 낼 수 있다.예 를 들 어 '프로 그래 밍 언어' 는 하나의 변수 가 될 수 있 고 'C 언어', 'Perl 언어', 'Lisp' 언어 등 으로 값 을 부여 할 수 있다.변 수 는 완충 사상 으로 이해 할 수 있 습 니 다. 한 컵 은 물 한 잔, 주스 한 잔, 술 한 잔 을 잠시 저장 할 수 있 습 니 다. 이 세 가지 이름 은 '액체' 라 는 변수 이름 으로 분류 할 수 있 습 니 다.
3. 환경
사실 백 마 는 말 에 속 하고 환경 도 변수의 일종 이다.다만 이 는 일반적으로 시스템 이 제공 하 는 것 으로 소프트웨어 가 실 행 될 때마다 변 수 를 설정 하 는 번 거 로 움 을 피하 기 위해 서 이다. 예 를 들 어 언어 를 설정 하 는 등 환경 이 있 으 면 바로 이런 변 수 를 사용 할 수 있다.일반적인 PATH, HOME. 명령 env 는 시스템 의 환경 변 수 를 볼 수 있 습 니 다.
우선 명령 행 분석 을 추가 하여 사용자 가 한 줄 에 명령 과 인 자 를 입력 할 수 있 도록 해 야 합 니 다.해상도 기 는 입력 한 줄 을 문자열 배열 로 나 누 어 하위 프로 세 스 의 execvp 에 전달 합 니 다.
신호 얘 기 좀 하 자.신 호 는 하나의 단어 로 구 성 된 메시지 로 프로 세 스 간 통신 에 사 용 됩 니 다. 프로 세 스 가 열심히 달리 고 있 습 니 다. 말 을 걸 려 면 종료, 정지 시 키 려 면 신 호 를 사용 해 야 합 니 다.kill - l 신호 목록 을 볼 수 있 습 니 다.
프로 세 스 처리 신 호 는 세 가지 상황 이 있 습 니 다. 하 나 는 기본 처리 이 고 보통 소멸 합 니 다. 이 호출 signal (SIGINT, SIG DFL) 은 SIGINT 의 기본 처 리 를 복원 합 니 다.둘째, 이 호출 signal (SIGINT, SIG IGN) 을 무시 합 니 다.셋째, 함수 signal (signum, function) 을 호출 합 니 다.
2) SIGINT 프로그램 종료 (interrupt) 신 호 는 사용자 가 INTR 문자 (보통 Ctrl - C) 를 입력 했 을 때 보 냅 니 다. 프론트 프로 세 스 그룹 에 프로 세 스 종 료 를 알 리 는 데 사 용 됩 니 다.
3) SIGQUIT
SIGINT 와 유사 합 니 다. QUIT 문자 (보통 Ctrl - \) 로 제어 합 니 다. 프로 세 스 는 SIGQUIT 가 종료 되 었 을 때 core (핵 토 출) 파일 을 생 성 합 니 다.
20) SIGTSTP
프로 세 스 실행 을 중지 하지만 이 신 호 는 처리 되 고 무시 할 수 있 습 니 다. 사용자 가 SUSP 문 자 를 입력 했 을 때 (보통 Ctrl - Z) 이 신 호 를 보 냅 니 다.
이 셸 에 서 는 SIGINT 와 SIGQUIT 를 처리 합 니 다. 셸 에 서 는 두 가 지 를 무시 하지만 하위 셸 에 서 는 기본 동작 을 복원 합 니 다. 셸 에서 하위 프로 세 스 를 끝 낼 수 있 기 때문에 셸 을 스스로 죽 이지 않 습 니 다.
셸 의 main 함 수 는 다음 과 같 습 니 다.
/* chicken_sh.c
 *   ,  .
 *         , egg_sh   
 */

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include "smsh.h"

#define DFL_PROMPT "> "

void setup();
void fatal(char *s1, char *s2, int n)


int main()
{
  char *cmdline, *prompt, **arglist;
  int result;
  
  prompt = DFL_PROMPT;
  setup();

  while ((cmdline = next_cmd(prompt, stdin)) != NULL) {
    if ((arglist = splitline(cmdline)) != NULL) {
      result = execute(arglist);
      freelist(arglist);
    }
    free(cmdline);
  }
  return 0;
}

void setup()
/*         
 */
{
  signal(SIGINT, SIG_IGN);
  signal(SIGQUIT, SIG_IGN);
}

void fatal(char *s1, char *s2, int n)
/*       
 */
{
  fprintf(stderr, "Error: %s, %s
", s1, s2); exit(n); }

함수 설명:
next_cmd  입력 에서 다음 명령 을 읽 고, 임의의 길이 파 라미 터 를 받 아들 이기 위해 malloc 로 메모 리 를 분배 합 니 다. 파일 이 끝나 면 NULL 로 돌아 갑 니 다.
splitline     파 라 메 터 를 분석 합 니 다. 문자열 을 문자열 배열 로 분해 하고 이 배열 로 되 돌려 줍 니 다.
chicken_sh 는 비교적 복잡 하기 때문에 코드 는 세 개의 파일 로 나 뉜 다. chickensh.c, splitline.c, execute.c  .(원본 다운로드)
이렇게 컴 파일:
gcc -o chichen_sh  chicken_sh.c splitline.c execute.c

그 중의 execute. c 는 변화 가 크 지 않 고 신호 처리 만 증가 했다.
splitline. c 는 좀 복잡 합 니 다. 설명 이 필요 합 니 다. 코드 는 다음 과 같 습 니 다.
/*splitline.c
 *  chicken_sh       
 *char *next_cmd(char *prompt, FILE *fp)        
 *char **splitline(char *str);                 
 */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "chicken_sh.h"

char *next_cmd(char *prompt, FILE * fp)
{
    char *buf;
    int bufspace = 0;
    int pos=0;		/*      */
    int c;		

    printf("%s", prompt);
    while ((c = getc(fp)) != EOF) {
	/*     */
	if (pos + 1 >= bufspace) {
	    if (bufspace == 0)	
		buf = emalloc(BUFSIZ);
	    else	
		buf = erealloc(buf, bufspace + BUFSIZ);	/*         */
	    bufspace += BUFSIZ;	
	}

	/*      */
	if (c == '
') break; /* , */ buf[pos++] = c; } if (c == EOF && pos == 0) return NULL; buf[pos] = '\0'; return buf; } #define is_delim(x) ((x) == ' ' || (x) == '\t') /* tab*/ char *newstr(char *s, int l); char **splitline(char *line) { char **args; /* */ int spots = 0; /* */ int bufspace = 0; /* */ int argnum = 0; /* */ char *cp = line; char *start; int len; if (line == NULL) /* */ return NULL; args = emalloc(BUFSIZ); /* */ bufspace = BUFSIZ; spots = BUFSIZ / sizeof(char *); while (*cp != '\0') { while (is_delim(*cp)) cp++; if (*cp == "\0") break; /* */ if (argnum + 1 >= spots) { args = erealloc(args, bufspace + BUFSIZ); bufspace += BUFSIZ; spots += (BUFSIZ / sizeof(char *)); } /* , \0 */ start = cp; len = 1; while (*++cp != '\0' && !(is_delim(*cp))) len++; args[argnum++] = newstr(start, len); } args[argnum] = NULL; return args; } /* * , '\0' */ char *newstr(char *s, int l) { char *rv = emalloc(l + 1); rv[l] = '\0'; strncpy(rv, s, l); return rv; } void freelist(char **list) /* , */ { char **cp = list; while (*cp) free(*cp++); free(list); } void *emalloc(size_t n) { void *rv; if ((rv = malloc(n)) == NULL) fatal("out of memory", "", 1); return rv; } void *erealloc(void *p, size_t n) { void *rv; if ((rv = realloc(p, n)) == NULL) fatal("realloc() failed", "", 1); return rv; }

emalloc 와 erealloc 는 잘못된 처 리 된 분배 공간 을 봉인 하 는 함수 입 니 다.
next_cmd 는 사용자 가 입력 한 명령 과 파 라 메 터 를 받 아들 여 링크 에 저장 합 니 다.
splitline 은 받 아들 인 매개 변 수 를 매개 변수 로 나 누 는 포인터 배열 을 담당 합 니 다. 공간 은 모두 동적 으로 분 배 됩 니 다. 사용자 가 명령 을 입력 할 때 각 매개 변 수 는 빈 칸 이나 tab 로 분리 되 어 있 기 때 문 입 니 다. newstr 는 그들 을 문자 독립 된 문자열 로 나 누 어 '\ 0' 으로 끝 냅 니 다.
컴 파일 된 chickensh, 일반 명령 을 실행 하 는 것 은 정상 셸 과 다 르 지 않 으 며, ctrl + D 를 누 르 면 종료 할 수 있 습 니 다.그리고 이 몇 가지 개선 도 할 수 있다.
1. 한 줄 에 여러 개의 명령 을 분점 으로 구분한다.
2. 백 스테이지 프로 세 스, 즉 명령 마지막 에 '&' 를 추가 합 니 다.
3. exit 명령 으로 종료 할 수 있 습 니 다. 종료 코드 를 설정 할 수 있 습 니 다. exit 1, exit 0 과 같 습 니 다.
다음 에 if. then 제어 문 구 를 추가 합 니 다.
셸 의 if 와 C 의 if 는 다른 점 이 있 습 니 다. C 에서 if 는 그 뒤의 문장 이나 괄호 로 싸 인 문장 블록 에 작용 하고 셸 은 then 으로 시작 합 니 다. "fi" 로 if 의 끝 을 표시 하면 실행 중인 프로 세 스 디자인 을 설명 하 는 데 간단 합 니 다.
그리고 if 는 명령 을 바탕 으로 0 으로 종료 하 는 것 이 성공 적 이라는 가설 입 니 다. 예 를 들 어:
if cat hello.c
then
echo hello
fi

cat 명령 이 성공 적 으로 실행 되 고 0 으로 돌아 가면 then 에서 fi 의 구문 블록 이 실 행 됩 니 다.명령 반환 0 과 if 뒤에서 0 을 직접 두 드 리 는 것 은 다 릅 니 다. 진 위 를 직접 설명 하려 면 true 와 false 를 사용 할 수 있 습 니 다. if true 는 if 뒤에서 성공 적 인 명령 을 수행 한 것 과 같 습 니 다. false 는 반대 입 니 다.
너무 길 어 요. 다음 편 에 쓰 겠 습 니 다.

좋은 웹페이지 즐겨찾기