CS(computer science)

[linux 뽀개기] - cd 명령어 구현하기

ebang 2023. 1. 5. 23:00
반응형

0. cd 명령어란? 

change directory라는 명령어의 줄임말로, 터미널에서 디렉토리를 오갈 때 사용하는 명령어이다. 

 

1. cd  명령어 형태

총 7가지로 정리했다.

 

cd [ 디렉토리 경로]

cd [relative_path] : 상대 경로

cd [absolute_path] : 절대 경로

 

cd .

현재 디렉토리로 이동

cd ..

 

한 단계 상위 디렉토리

cd /

최상위 디렉토리로 이동

cd $(변수명)

변수에 저장된 경로로 이동 (파싱 과정에서 $(변수명) 파싱 이후에는 맨 위와 동일하게 처리 되므로 문제 없다)

 

cd
cd $(HOME)
  • 사용자 홈 디렉토리로 이동

 

cd -
  • 이전 경로로 이동

 

* cd ~ 같은 명령어의 경우,  symbolic path라고 해서 절대 경로, 상대 경로 말고 이외의 처리인데, 구현에서는 처리하지 않았다. 

 

 

2. 형태에 따른 구현법

1. cd .

아무것도 하지 않는다.

2. cd ..

상위 디렉토리로 이동: pwd에서 /이전으로 옮긴 다음, 해당 폴더로 이동

3. cd /

최상위 디렉토리를 찾아서 이동

4. cd

home 디렉토리로 이동. (cd $(HOME)의 경우 1의 경우와 동일, but 환경변수 설정안되어있는 경우 유의)

5. cd ~계정명

입력한 사용자의 홈 디렉토리로 이동 (사용하나 여기서도?)

6. cd -

이전 경로를 찾아서 이동

7. cd - -

home 디렉토리로 이동


3. 구현 생각해보기

  • parsing을 통해 경로를 얻는다.
  • 각 경우에 pwd 변경 : env에서 변경한다. (환경변수 PWD, OLDPWD에 현재 위치, 이전 위치가 저장되어있는데 직접 지정해주어야 한다. )
    • PWD 변수의 value 값이 OLDPATH의 value 값으로.
    • getcwd() 함수의 값이 PATH의 value 값으로.
  • env (환경변수) 에는 현재 디렉토리, 이전 디렉토리 경로가 각각 PWD, OLDPWD에 저장되어있다!
  • cd ~는 구현하지 않는다 : symbolic 경로의 경우 구현하지 않기로 했다.

<special cd>

  1. 4번의 그냥 ‘cd’만 있는 경우, 7번의 ‘cd - -’ 인 경우, 모두 HOME 환경변수를 찾은 후 그 경로로 chdir()함수를 사용하는 방법을 사용한다.
HOME, PWD, OLDPWD 환경변수가 없는 경우 에러를 출력하도록 한다. 
(이러한 에러 처리의 경우 zsh, bash 등이 모두 다르다. 
HOME 환경변수 혹은 PWD 환경변수 등이 존재하지 않는 경우에도 
zsh는 정상 동작하는데 굉장히 신기한 실습들이 있다.)
  1. 6(cd -)

OLDPWD 환경 변수 값을 경로로 불러와서 chdir를 수행한다.

OLDPWD 환경변수가 세팅되지 않은 경우 에러를 출력한다. (단, 터미널마다 이러한 에러 처리는 모두 다르다.)

cd — [path] 명령도 된다.

 

4. 생각해볼 점

💡 goinfre는 symbolic path라고 한다. 그래서 경로가 조금 달라지는 문제가 생긴다.(goinfre에서 getcwd사용)
💡 상위 폴더를 삭제하고 났을 때 pwd, cd . 명령어를 사용할 때 상이한 출력 및 처리를 한다.
💡 cd - 명령어처럼 이전 디렉토리로 가는 경우
환경변수에서 OLDPATH의 값을 가져와서 chdir(path), 
cd 명령어처럼 home 디렉토리로 가는 경우, HOME의 값을 가져와서 chdir(path)를 실행한다. 
이때, 환경변수가 존재하지 않는다면 (unset PWD, unset HOME, unset OLDPWD)
에러가 발생할 수 있는데, 터미널 종류에 따라서 그 처리가 다르다. 
bash의 경우에는 아래와 같은 처리를 한다.

반면 zsh의 경우, 다른 동작을 하나 여기서 언급하지 않겠다. 

💡 현재 폴더에서 상위 폴더를 삭제하는 경우에도 동작이 다르다. zsh같은 경우 상위 폴더가 사라지면 현재폴더의 위치가 
.으로 표시되는 반면, bash에서는 에러가뜬다.

이를 위한 실습은 다음과 같다. 

1. mkdir -p 옵션을 이용해서 여러 연속된 하위 폴더들을 만들고, 
가장 마지막 폴더에 접근한다.

mkdir -p a/b/c/d/e
cd a/b/c/d/e

 

2. 가장 하위 폴더에 접근한다음, 상위폴더를 삭제한다. 
cd a/b/c/d/e
rm -rf ~/a/b
3. 확인을 위해 현재 위치를 출력해보거나 상위 폴더로 이동해본다. 

pwd
cd ..

bash의 경우 cd .. 을 입력했을 때 오류가 뜬다. 

반면 zsh는 오류 없이 정상작동 한다 . 

단 현재 위치가 '.'으로 표시된다 .

 

나는 오류를 bash에 맞추어서 짰다. 

 

5. 대략 짰던 pseudo code

#include "../inc/minish.h"
#include "../inc/include.h"

static char	*cd_find_path(int argc, char **argv)
{
	int	i;

	i = -1;
	if ((argc > 1 && !ft_strcmp(argv[1], "--")))
		return (argv[2]);
	if (argc == 1)
		return (NULL);
	while (*argv[++i] != 0)
	{
		if (argv[i][0] == 'c' && argv[i][1] == 'd')
			break ;
	}
	i++;
	return (argv[i]);
}

int ft_set_pwd(char ***env)
{
	//OLDPWD에 PWD 저장.    <- 오류 가능성: PWD 환경변수 unset 되어있을 때. (나의 오류처리: 오류 출력)
	//PWD에 getcwd 저장. <- 오류 가능성: symbolic path 인 goinfre에. (나의 오류처리: Undefined)

}

int cd_go_HOME(char ***env)
{
	//pwd환경변수 불러옴.   <- 오류 가능성: PWD 환경 변수 unset되어있을 때. (나의 오류처리: 오류 출력)
	//그 경로로 chdir함. 
	
}

int cd_go_back(char ***env)
{
	//oldpwd환경변수 불러옴.   <- 오류 가능성: PWD 환경 변수 unset되어있을 때. (나의 오류처리: 오류 출력 - bash 처럼)
	//그 경로로 chdir함. 
	
}

int	ft_cd(int argc, char **argv, char ***env)
{
	int		ret;
	char	*path;

	ret = 0;
	path = cd_find_path(argc, argv);
	if (!path)
	{
		if (!cd_go_home(env))
			return (-1);
	}
	else if (!strcmp(path, "-"))
	{
		if (!cd_go_back(env))
			return (-1);
	}
	else if (chdir(path))
	{
		ft_builtin_error4("minishell", "cd", path, "no such file or directory");
		return (-1);
	}
	ret = ft_set_pwd(env);
	return (ret);
}

 

 

 

6. 참고 사이트

https://iq.opengenus.org/implementing-cd-command-in-c/

 

Implementing cd command in C/ C++

We have developed the cd command of UNIX systems in C and C++ by using the chdir function.

iq.opengenus.org

https://www.linuxquestions.org/questions/programming-9/how-do-i-implement-a-cd-builtin-to-a-c-shell-4175549435/

http://web.archive.org/web/20090515201659/http://www.cs.ucr.edu/~brett/cs153_w02/syscall.html

 

http://web.archive.org/web/20090515201659/http://www.cs.ucr.edu/~brett/cs153_w02/syscall.html

.align 4 _system_call: pushl %eax # save orig_eax SAVE_ALL movl $-ENOSYS,EAX(%esp) cmpl $(NR_syscalls),%eax jae ret_from_sys_call movl _sys_call_table(,%eax,4),%eax testl %eax,%eax je ret_from_sys_call movl _current,%ebx andl $~CF_MASK,EFLAGS(%esp) # clear

web.archive.org

 

 

*전체 코드를 보기 원하신다면 댓글로 이메일을 남겨주시면 보여드리겠습니다!

반응형