Study with Me!
Seongmo
Study with Me!
전체 방문자
오늘
어제
  • Computer (126)
    • Computer Science (61)
      • Data Structure (51)
      • Algorithm (6)
      • 선형대수 with C++ (4)
    • Arm Architecture (1)
      • Register (0)
      • Assembly Instruction (1)
    • Linux (30)
      • Linux Kernel (4)
      • 라이브러리 함수 구현하기 (0)
      • 쉘, 쉘 명령어 구현하기 (15)
      • Ubuntu (11)
    • AWS (3)
    • Baekjoon (18)
    • Tools (6)
      • Git & Github (5)
      • Vim (1)
    • 개발 환경 (7)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • STL

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Study with Me!

Seongmo

[쉘 구현하기] ls 명령어 구현
Linux/쉘, 쉘 명령어 구현하기

[쉘 구현하기] ls 명령어 구현

2023. 8. 9. 07:43

ls 명령어를 구현했다.아직 옵션을 주거나 경로를 지정하는 기능은 구현하지 않았고, 현재 디렉토리 기준으로만 가능하다.숨김 파일과 . .. 디렉토리도 출력하지 않는다. (-a 옵션 추가 예정)

zsh에서 ls 명령어를 사용하면 리스트 중 (가장 긴 파일명 + 1)의 공간으로 파일들이 출력되는 것을 알 수 있다.

이것을 만들기 위해 파일 목록을 연결리스트에 저장하고 가장 긴 파일명을 저장했다.

 

터미널 창의 사이즈에 따라 한 줄에 출력되는 파일의 개수가 달라졌는데 그것은 어떻게 해야할 지 아직 모르겠다.

그래서 한 라인에 8개의 파일만 출력되도록 구현했다.

 

파일(디렉토리) 목록은 opendir(), readdir()을 통해 읽었다.

// my_ls.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>

typedef struct _node {
    char *fileName;
    struct _node *next;
} Node;

Node *head = NULL;
int maxLength = -1;

void addNode(Node *newNode) {
    if (head == NULL) {
        head = newNode;
    }
    else {
        Node *cur = head;

        while (cur->next != NULL) {
            cur = cur->next;
        }
        cur->next = newNode;
    }
}

void deleteNode() {
    while (head != NULL) {
        Node *del = head;
        head = head->next;
        free(del);
    }
}

Node *createNode(char *fname) {
    Node *ret = (Node *)malloc(sizeof(Node));
    ret->next = NULL;
    ret->fileName = fname;

    return ret;
}

void makeList() {
    DIR *dp;
    struct dirent *entry;
    struct stat statbuf;

    if ((dp = opendir(".")) == NULL) {
        fprintf(stderr, "opendir error\n");
        exit(1);
    }

    while ((entry = readdir(dp)) != NULL) {
        if (stat(entry->d_name, &statbuf) < 0) {
            fprintf(stderr, "stat error\n");
            exit(1);
        }

        Node *newNode = createNode(entry->d_name);
        addNode(newNode);
        if ((int)strlen(newNode->fileName) > maxLength)
            maxLength = (int)strlen(newNode->fileName);
    }

    maxLength++;
    closedir(dp);
}

void ls() {
    makeList();

    Node *cur = head;
    int cnt = 0;
    while (cur != NULL) {
        if (cur->fileName[0] == '.') {
            cur = cur->next;
            continue;
        }
        int tab = maxLength - (int)strlen(cur->fileName);
        printf("%s", cur->fileName);
        for (int i = 0; i < tab; i++) {
            printf(" ");
        }
        cur = cur->next;
        cnt++;
        if (cnt % 8 == 0)
            printf("\n");
    }

    deleteNode();
    printf("\n\n");
}
// SM_shell.c
#include "my_header.h"
...
void lsExec() {
    pid_t pid;

    if ((pid = fork()) < 0) {
        fprintf(stderr, "fork error\n");
        exit(1);
    }
    else if (pid == 0) {
        execl(execName, "ls", (char *)0);
        exit(0);
    }
    else {
        pid = wait(NULL);
    }
}

void init() {
    getcwd(execPath, PATH_MAX);
    sprintf(homePath, "%s", getenv("HOME"));
}

void prompt() {
    char input[STR_MAX];
    int command;

    while (1) {
        printf("SM_shell > ");
        
        fgets(input, STR_MAX, stdin);
        input[strlen(input) - 1] = '\0';

        if (!strcmp(input, "clear")) {
            system("clear");
            continue;
        }

        if (!strcmp(input, commandList[0])) { // exit
            fprintf(stdout, "* SM_shell exit... *\n");
            exit(0);
        } else if (!strcmp(input, commandList[1])) { // help
            command = CMD_HELP;
        } else if (!strcmp(input, commandList[2])) {
            printf("%s\n\n", execPath);
            command = CMD_PWD;
            continue;
        } else if (!strcmp(input, commandList[3])) {
            command = CMD_LS;
        }
        else {
            command = NOT_CMD;
        }

        if (command & CMD_HELP || command == NOT_CMD) {
            helpExec();
        } else if (command & CMD_LS) {
            lsExec();
        }
    }
}

int main(int argc, char **argv) {
    init();

    strcpy(execName, argv[0]);

    if (!strcmp(argv[0], "help")) {
        help();
    } else if(!strcmp(argv[0], "ls")) {
        ls();
    }
    else {
        prompt();
    }

    exit(0);
}

위 코드는 아래 이미지를 클릭해 깃허브에서도 확인할 수 있다.

깃허브 이미지 링크

저작자표시 (새창열림)

'Linux > 쉘, 쉘 명령어 구현하기' 카테고리의 다른 글

[쉘 구현하기] execv() 사용을 위한 문자열 배열 만들기  (0) 2023.08.11
[쉘 구현하기] ls 명령어 터미널 크기에 최적화  (0) 2023.08.09
[쉘 구현하기] pwd 명령어 구현  (0) 2023.08.08
[쉘 구현하기] help 명령어 구현  (0) 2023.08.08
[쉘 구현하기] 쉘 초기 형태  (0) 2023.08.08
    'Linux/쉘, 쉘 명령어 구현하기' 카테고리의 다른 글
    • [쉘 구현하기] execv() 사용을 위한 문자열 배열 만들기
    • [쉘 구현하기] ls 명령어 터미널 크기에 최적화
    • [쉘 구현하기] pwd 명령어 구현
    • [쉘 구현하기] help 명령어 구현
    Study with Me!
    Study with Me!
    Study with Me!

    티스토리툴바