ls나 cd는 뭔데 그냥 입력해도 동작하나? 예약어의 기원이 궁금해

환경변수 정리

  • cc: c compiler
  • gcc: gnu compiler collection. GNU 프로젝트의 일환으로 개발되어 쓰이는 컴파일러.

리눅스에서는 gcc가 기본으로, gcc가 자동으로 cc로 연결되어 사용되도록 함.

일반적인 실행파일의 경우, 해당 실행파일이 존재하는 디렉토리에 접근해야 실행 가능하게된다.

일반적인 바이너리 파일을 열게 되면, 다음과 같이 나온다(2진수 포맷).

이렇게 기계어로 정리된 파일을 실행파일로 사용하게 된다.

xxd -b binary
---
...
00e625a8: 10111010 01010101 01001111 10110010 11010101 11010110  .UO...
00e625ae: 11100111 11000101 01011111 01001000 11101111 11110001  .._H..
00e625b4: 11111110 11111101 00110010 00000010 11000100 10100100  ..2...
00e625ba: 00000000 00111011 11011011 00110000 10110100 11001011  .;.0..
00e625c0: 01101011 11100110 01000000 11110101 10000001 10010001  k.@...
00e625c6: 10100010 11010100 00011100 11001100 11111101 00101001  .....)
00e625cc: 10000011 10111010 10011001 11111010 11101010 00110000  .....0
00e625d2: 00001011 10110110 00100000 01101010 10011000 10011100  .. j..
00e625d8: 00011000 01110010 10101110 00001001 10111001 11111001  .r....
00e625de: 10100101 10010001 00010110 00110010 11111000 10111010  ...2..
00e625e4: 00111100 11001101 11011000 10100111 00011010 10111100  <.....
00e625ea: 10110111 11101110 00100100 10100101 11111100 11110011  ..$...
00e625f0: 10110010 01110010                                      .r

환경변수 파일은 이러한 바이너리 파일을 글로벌하게 수행할 수 있도록 돕는 역할을 한다.

echo $PATH

ls도 이러한 실행 파일을 수행하는 것과 동일하다. ls의 위치를 알아보자.

# which ls는 alias to ls -G라고만 뜬다. root권한으로 확인하자.
sudo which ls
---
/bin/ls

해당 경로로 이동해서 어떤 파일이 존재하나 살펴보자.

cd /bin
---
[         chmod     dash      df        expr      ksh       ln        mv        pwd       rmdir     stty      test      zsh
bash      cp        date      echo      hostname  launchctl ls        pax       realpath  sh        sync      unlink
cat       csh       dd        ed        kill      link      mkdir     ps        rm        sleep     tcsh      wait4path

평소 자주 보던 친구들이 존재한다. 말고도 /usr/bin 아래에 더더더욱 많은 파일들이 존재한다.

평소 우리가 자주 사용하는 친구들이 전부 이곳에 존재했다.

Path

:로 구별되는 여러 경로가 포함된 문자열이며, 셸은 경로가 포함되지 않은 명령어가 입력되었을 때 path를 :를 기준으로 나눈 뒤 그 경로들을 모두 입력된 명령어 앞에 붙여보면서 실행 가능한지 여부를 확인한다.

그럼 여러 path가 가능하면은 먼저 검색되는 순서대로. path 기준 앞쪽에 있어야 한다.

Shell

셸(Shell)은 명령어 입력기이자 실행기로, 명령어를 해석하고 실행하는 인터프리터이다. 명령어는 크게 2가지로 나뉜다.

  1. 내부 명령어: 셸 자체에서 제공하는 명령어. cd, echo, export 같은 명령어는 셸에 내장되어 있어 별도의 바이너리 파일이 존재하지 않는다.
  2. 외부 명령어: 시스템에 설치된 프로그램이나 스크립트를 실행한다. ls, grep, python과 같은 명령어는 전부 시스템 특정 경로 내에 존재하는 파일로 실행된다. 이 경우, 셸은 PATH에 명시된 디렉토리를 통해 파일을 찾고 실행한다.

실제로 which pwd를 입력하면 아래와 같이 뜬다.

which pwd
---
pwd: shell built-in command

이러면 바이너리 파일이 제공되지 않는 내장 명령어임을 알 수 있다.

이외에 이러한 경우도 존재한다.

which cd
---
cd () {
	if __gvm_is_function __gvm_oldcd
	then
		__gvm_oldcd $*
	fi
	local dot_go_version dot_go_pkgset rslt
	local defaults_go_name defaults_go_pkgset
	local defaults_resolved=false
	local defaults_hash
	defaults_hash=()
	if [[ "$GVM_ROOT" == "" ]]
	then
		display_error "GVM_ROOT not set. Please source \$GVM_ROOT/scripts/gvm"
		return $?
	fi
...

이렇게 내장 명령어의 경우에도 셸 설정을 통해 별도의 설정을 추가해주는 경우, 해당 설정이 포함된 형태로 명령어가 재구성된다.

현재 나의 cd명령어는 go 버전 관리 도구인 gvm 설정과 관련한 작업이 추가되어 있기에 이렇게 로직이 드러난다.

해당 세션에서만 설정을 제거하여 실재 내장 명령어인지 다시 확인해보자.

unset -f cd
which cd
---
cd: shell built-in command

세션 한정으로 설정을 제거하면, 바로 내장 명령어임이 드러난다.

영구적인 설정 제거를 원한다면 셸 설정 파일에서 제거하자.