메뉴

문서정보

2장 리눅스와 C언어

목차

Linux 와 C

최초에 C는 시스템:::프로그래밍(:12)을 위한 언어로 개발되었으며, 상업적 및 학습적인 용도로 성공한 최초의 운영체제라 할 수 있는 Unix(:12)운영체제를 만드는 데에 사용되었다. 한마디로 Unix와 C는 뗄레야 뗄 수 없는 관계인 것이다. 이견이 있을 수 있지만 운영체제의 선조격인 Unix를 이해하는 것은 컴퓨팅환경을 이해하는 가장 좋은 방법이며, Unix를 이해하는 가장 좋은 방법은 C를 이해하는 것이라 할 수 있다.

Linux(:12) 운영체제가 Unix(:12)와 전혀 다른 운영체제라고는 하지만 Unix(:12)의 모든 철학과 구현을 그대로 포함하고 있으며, 사실상 또다른 Unix운영체제의 한 종류라고 할 수 있다. Unix의 또다른 운영체제라는데 거부감을 가진 리눅서들도 있겠지만 프로그래머의 입장에서 보자면 Linux와 Unix는 동일하다.

굳이 Linux환경에서 C언어를 공부하려는 이유가 여기에 있다. Linux를 이해한다는 것은 Unix를 이해한다는 것이며, 이는 컴퓨팅환경을 이해한다는 의미가 되기 때문이다.

Linux! 에 대해서

Linux의 탄생

필린드 헬싱키 대학원에서 소프트웨어:::공학(:12)을 전공하던 많은 학생들중 linus:::Torvalds(:12)라는 평범한 대학원생이 있었다. 당시 토발즈는 Andrew Tanenbaum교수에 의해서 개발된 Minix(:12)라는 운영체제를 가지고 Unix 시스템에 대한 공부를 하고 있었는데, Minix의 라이센스와 성능등이 자신이 원하는 바에 미치지 못함을 알게 되었다.

그리하여, 나름대로 Unix-like한 운영체제를 만들 계획을 세우고 이를 실행에 옮기게 된다. 이러한 실행의 결과물로 탄생한게 Linux(:12)다.

Linux는 애시당초 개인이 취미삼아서 만든 운영체제 이므로, 그 시작은 매우 보잘 것이 없었다. 이러한 Linux운영체제가 개인사용자부터 대기업환경에 까지 널리 사용되게 된것은 인터넷(:12)과 GNU(:12)의 공로가 절대적이였다.

리누즈는 별 생각 없이 1991년에 자신이 만든 linux(version 0.01)를 뉴스그룹을 통해 공개하게 된다. 공개를 발표하면서 그는 "이는 단지 취미이며 GNU처럼 전문적인 것이 아니다"라고 발표소감을 표현했다. 말그대로 취미삼아 공개했던 linux는 수많은 유능한 프로그래머의 자발적인 참여로 급속한 발전을 이루게 되었으며, 결국 GNU의 여러 프로젝트중 가장 중요한 프로젝트로 이름을 올리는 수준까지 이르게 된다.

이렇게 빠른 성장을 하긴 했지만, 1998년 까지는 학습용 운영체제라는 이미지가 강했다. 그러던 것이 리눅스의 시장에서의 잠재적 성장능력을 눈치챈 레드햇과 같은 몇몇 회사들에 의해서 기업시장의 물꼬가 트이게 된다.

현재는 어떤 소프트웨어 벤더라도 리눅스를 무시할 수 없는 정도가 되었다. IBM(:12), Dell, Oracle(:12), Informix, Intel 등이 전략적으로 Linux를 유/무형으로 지원하고 있다.

Linux의 특징

프로그래머의 관점에서 Linux의 특징을 살펴보도록 하겠다.

많은 Linux와 GNU(:12)지지자들이 Linux는 Unix가 아니다라고 하고 있다. 그러나 개발자 입장에서 Linux는 분명 Unix-like한 운영체제다. 실제 Linux 운영체제는 Unix의 여러 철학들을 그대로 적용시키고 있다. 파일, IPC(:12), 각종 시스템/표준지원 함수등 모든 것이 Unix환경과 동일하거나 비슷하다. 컴퓨팅역사에서 사실상 최초로 등장한 운영체제는 Unix이며, Unix 운영체제의 철학과 설계, 구성은 후에 등장한 모든 운영체제들이 계승하고 있다. 유닉스의 최대? 경쟁상대인 windows도 예외가 아니다. 이는 Unix는 컴퓨팅분야의 학습을 위한 최고의 운영체제임을 의미한다. 그러나 안타깝게도 이러한 Unix운영체제를 직접 운영하는데에는 "비용"이라는 결정적인 문제가 따르게 된다. Unix운영체제는 매우 비싸며, 상대적으로 고가의 장비에서 돌아가기 때문에, 실무를 뛰는 개발자가 아닌, 학생(혹은 백수)의 신분에서 접하기란 결코 쉽지 않다. Linux는 훌륭한 대안이 될 수 있다. Linux는 Unix의 철학을 그대로 계승하고 있으며, 시스템의 모든 것이 Unix와 거의 동일하다. 시스템 명령, 툴들도 동일하게 사용할 수 있으며, Linux에서 만든 프로그램은 거의 수정없이 Unix에서 그대로 사용될 수 있다. 게다가 자유롭게 이용할 수 있으며, 저렴한 PC에서도 훌륭하게 작동된다.

Unix가 학습을 위한 최고의 운영체제(:12)라는 의견에 대해서는 이견이 있을 수 있다. 필자의 생각을 정리해 보자면 Unix가 최고의 학습용 운영체제인 이유는 다음과 같다.
  1. Unix는 모든 운영체제의 선조격이다. 대부분의 운영체제가 Unix운영체제 모델을 거의 그대로 따르고 있다.
  2. Network:::programing(:12), system:::programing(:12)을 위한 라이브러리(:12)와 툴, 프로토콜(:12)들이 Unix 환경에서 만들어졌다.
  3. RFC, 개발문서의 상당수가 Unix 기준이다(역사가 오래되었기 때문에 당연하다)
  4. 단순한 계층을 가지고 있다. - 윈도우즈 같은 경우는 사용자 편의를 위해서 여러개의 계층을 가지게 된다. 이는 저 깊숙이에 있는 계층을 직접 접근해야 하는 개발자에게는 재앙이 될 수 있다 -
  5. Unix의 철학은 Small is beautifull이다. 이러한 철학은 일반유저에게 불편함으로 다가올 수 있지만 개발자나 프로그래머 학생에게는 장점이 된다. 에디터와 gcc(:12)컴파일러 하나가 갖추어지는 것으로 학습/개발환경이 만들어진다.

C 언어

언어에 대해서

언어는 의사소통을 위한 수단으로 사용된다. 일본인과의 의사소통을 위해서는 일본어를 구사해야 한다. 중국인, 미국인과도 마찬가지가 되겠다. 사람사이의 의사소통을 위해서만 언어가 사용되느냐 하면 그렇지도 않다. 무언가를 제어하고 다루기 위한 모든 부분에 언어는 사용된다. 자연현상을 이해하기 위해서 수학이 사용된다. 기계를 다루기 위해서 제공되는 메뉴얼 역시 언어라고 할 수 있다.

C 프로그래밍 언어

컴퓨터와 대화하기 위해서는 컴퓨터가 이해할 수 있는 언어인 기계어를 사용해야 한다. 예를 들어서 주어진 숫자들의 목록에서 가장 큰 숫자를 찾도록 할려면 대략 다음과 같은 언어를 컴퓨터에 입력해야 한다.
0011010011101011100101100100111010000000010101000010110110001010...
한마디로 말해서 인간이 할 짓이 되지 못한다. 도대체 저걸 어떻게 이해하고 명령을 내릴 수 있단 말인가. 그러나 놀랍게도 컴퓨터가 만들어진 초기에는 저러한 기계어를 직접 컴퓨터에 입력하는 방식으로 컴퓨터를 운용했었다.

원래 인간은 게으른 동물이다. 많은 컴퓨터과학자들이 위의 단순무식한 방법이 아닌 좀더 쉬운 방법으로 컴퓨터와 대화하기 위한 방법을 찾기 위해서 노력했었고, 그래서 만들어진게 Assembly(:12) 이다. Assembly는 01된 명령을 좀더 인간이 이해하기 쉽게끔 문자화 했다.
.section .data

data_items:                         # 숫자 데이터들
    .long 3,67,34,222,45,75,54,34,44,33,22,11,66,0 
    .section .text
    .globl _start

_start:
    movl $0, %edi                   # move 0 into the index register
    movl data_items(,%edi,4), %eax  # load the first byte of data
    movl %eax, %ebx                 # since this is the first item, %eax is
                                    # the biggest

start_loop:                         # start loop
    cmpl $0, %eax                   # check to see if we ve hit the end
    je loop_exit
    incl %edi                       # load next value
    movl data_items(,%edi,4), %eax
    cmpl %ebx, %eax                 # compare values
    jle start_loop                  # jump to loop beginning if the new
                                    # one isn t bigger
    movl %eax, %ebx                 # move the value as the largest
    jmp start_loop                  # jump to loop beginning
loop_exit:                          # %ebx is the return value,
                                    # and it already has the number

    movl $1, %eax                   #1 is the exit() syscall
    int $0x80
뭐 그래도 여전히 보기 어렵다고 생각할지 모르겠지만 어쨋든 기계어(:12)보다는 훨씬 이해하기 쉬울 것이다.

그러나 어셈블리어(:12)는 기계어를 1:1로 전환한다. 때문에 기계어 보다는 획기적으로 이해하기 쉽지만, 여전히 인간에게 기계적인 사고방식을 강요하게 만든다.

그래서 좀더 인간적인, 좀더 인간이 사용하기 쉬운 또다른 대안을 찾게 되었고, 그러한 노력의 결과 만들어진게 C언어이다. C 프로그래밍 언어 (이하 C)는 1970년에 Unix(:12)운영체제에서 사용하기 위한 목적으로 Dennis:::Ritchie(:12)에 만들어 졌으며, 강력함과 편리함으로 거의 모든 컴퓨터와 운영체제에서 사용하는 가장 성공적인 프로그래밍 언어가 되었다.

이후에 만들어진 C++, Java(:12), Perl, PHP(:12), Python 등의 언어들도 직간접적으로 C의 영향을 받았다. 최근들어 이들 최신의 언어가 많은 인기를 끌고 있기는 하지만, 여전히 C는 가장 많은 개발자진을 확보 하고 있으며, 많은 수의 프로그램이 여전히 C로 만들어지고 있다.

다음은 C로 만들어진 가장 큰 숫자를 찾는 프로그램이다.
int main()
{
	int i = 0;
	int maxitem = -1;
	int items[] = {3,67,34,222,45,76,54,34,44,33,22,11,66,0};
	while(items[i] != 0)
	{
		if (items[i] > maxitem)	
			maxitem = items[i];
                i++;
	}
	printf("MAX NUM IS : %d\n", maxitem);
}
약간의 센스만 있다면 프로그래머가 아니더라도 이해하기 어렵지 않을 정도다.

엄격히 말하자면 C언어라는 것은 인간이 기계어를 이해하고 사용하기 힘들기 때문에 만들어진 중간단계의 언어라는 것을 알 수 있다. 위의 코드는 인간은 쉽게 이해할 수 있지만 컴퓨터는 이해할 수 없기 때문에, 기계어로 바꾸어주는 컴파일러(:12)라는 별도의 프로그램이 필요하게 된다. 이것은 나중에 다루도록 할 것이다.

컴퓨터와 운영체제 그리고 프로그래밍 언어

컴퓨터 , 운영체제는 라고 할 수 있다. 그러나 뇌만 가지고서는 할 수 있는 일이 제한적이다. 최소한의 컴퓨터의 유지만 가능할 뿐이고, 어떤 원하는 일을 하기 위해서는 프로그램이 필요하다. 프로그래밍 언어란 이러한 프로그램을 만들기 위한 또다른 프로그램셋 이라고 이해하면 된다.

왜 Linux와 C 인가

지금에 와서 C는 C++, Java, Perl, Python, Ruby, C# 등의 언어들에 비해서 구닥다리 언어로 취급을 받고 있는게 사실이다. 그러나 여전히 C는 많은 영역에서 쓰여지고 있으며, 만들어지는 전체 프로그램의 (아마도) 적어도 60% 이상이 C로 만들어지고 있다. C는 여전히 성공적으로 사용되고 있는 언어이다. 아래에 C를 배워야할 이유를 설명하고 있다. C는 실질적으로 성공한 가장 오래된 언어이다. 그만큼 오랜 역사를 가지고 있음을 의미한다. 역사를 알면 시대를 지배할 수 있다. 프로그래밍 기술을 익히는 가장 좋은 방법중 하나는 다른 훌륭한 프로그램을 접하는 것이다. 수십라인의 간단한 프로그램부터 수만/수십만 라인의 거대한 프로그램까지 수많은 C로 된 프로그램들을 인터넷상에서 접할 수 있다. 알고리즘과 자료구조등을 설명한 대다수의 문서들이 C를 기준으로 테스트되어지고 작성되어서 배포되고 있다. 최근에는 (특히 Python) 다른 언어들로 설명되어진 문서들이 나오고 있지만, 역시 절대다수의 문서들이 C를 기준으로 만들어 지고 있다. 문서의 작성자들이 C언어에 익숙한 경우가 많기 때문이다. 단점이 될 수도 있겠지만, C는 간결하고 단순하다. 이는 다른 부가적인 것에 신경안쓰고, 배우고자 하는 언어의 특징과 활용에 집중할 수 있도록 도와준다.

결론적으로 말하자면 Linux 환경을 이러한 C언어를 배우는데 최적의 환경을 제공한다. 운영체제의 선조격인 Unix의 철학을 그대로 가지고 있으며, 표준을 잘 따르고 있다. 설치 즉시 별도의 비용을 지불할 필요 없이 완전한 개발환경(:12)을 구축해준다. 복잡하고 머리아프게 이런저런 라이센스 따지면서 개발환경을 만들 필요가 없으며, 잡다한 것에 신경쓰지 않고, 오로지 개발과 학습에 집중할 수 있도록 도와준다. Linux에서의 C개발환경이 정말 그렇게 환상적인가에 대해서는 이견이 있을 수 있지만, 적어도 학습에 있어서 최상의 환경을 제공해준다는걸 의심할 필요가 없을 것이다.

언어형식으로써의 C

언어는 또한 형식에 따라 분류가 가능하다. 가장 대표적인 경우가 영어, 일어, 불어와 같은 구술언어와 과학의 언어로 사용되는 수학일 것이다. 이 두가지는 장단점을 가진다. 예컨데, 인간의 언어는 인간의 일상적인 생활에서 사용하는데 적당하다. 인간적, 즉 직관적이기 때문이다. 반면 그다지 간결하지 못하며 문화와 지역, 교육수준등에 따라서 의미가 명확하지 못하거나 전혀 다르게 해석될 수 있다는 문제점을 가진다. 일상생활에서는 문제가 없지만, 객관적인 정보가 중요한 영역 예컨데 자연과학 분야에서 인간의 언어를 사용하는데에는 문제가 될 소지가 충분하다.

이러한 문제를 해결하기 한 언어가 수학이다. 수학은 제한된 기호를 이용해서 정보를 전달하는 또다른 언어체계다. 매우 간결하며, 기호의 의미를 이해하고 있다면 문화와 가치관 지역, 역사에 관계없이 동일하게 해석이 될 수 있다. 자연과학에서 정보전달을 위해 수학을 이용하는 것은 이러한 이유에서 이다.

C언어는 어떤 특징을 가질까 ?

언뜻 생각하기에 컴퓨터라는 도구가 과학과 기술의 산물이기 때문에, 수학과 같은 형식을 취할 거라고 생각할 수 있을 것이다. 그러나 C언어는 인간언어와 유사한 특징을 가진다. 왜냐하면 인간은 일상생활의 대부분의 문제를 인간의 언어를 이용해서 해결해 왔었고 역시 프로그래밍 언어도 가능한 인간이 쉽게 사용할 수 있는 형태가 유리했기 때문이다.

C언어는 이러한 측면에서 절차적 언어로 구분한다. 인간의 언어로 서술되는 형식을 따르기 때문이다.

그러나 인간의 언어가 모든 부분에서 효율적이지 않은 것처럼, 절차적 언어로써의 C역시 모든 문제를 푸는데 있어서 결코 효율적이지는 않다. 초기 컴퓨터가 푸는 문제가 비교적 단순할 때에는 크게 문제가 되지 않았지만, 데이터의 양이 커지고 문제가 복잡해지자 C언어의 절차지향적인 특징의 한계가 점점 나타나기 시작했다.

이러한 한계를 극복하기 위해서, 객체지향언어, 함수형 언어등이 등장하게 된다.

객체지향언어라면 아마도 많이 들어보았을 것이다. C++, Java, Python, Ruby.. 등 최근등장하는 프로그래밍언어들은 한결같이 객체지향적인 특징을 가지고 있다. 함수형언어는 문제를 서술해서 푸는게 아닌, 함수만을 이용해서 풀어내는 방식으로 기호만을 이용해서 문제를 푸는 수학비슷한 형식의 언어다.

Start Linux

이 문서는 리눅스 활용서가 아니다. 그러므로 프로그래밍을 함에 있어서 반드시 필요하다고 생각되는 리눅스의 특징적인 것들에 대해서 알아보도록 할 것이다.

Linux Kernel

실질적으로 운영체제라고 하면 Kernel(:12) 자체를 가르킨다. kernel이야말로 뇌에 해당되는 핵심적인 부분으로 램, 키보드입력, 모니터 출력, 프로그램 제어와 같은 핵심적인 업무를 수행한다. 나머지는 모두 kernel위에서 돌아가는 (형태가 다른) 프로그램일 뿐이다.

Linux 커널은 리누즈 토발즈가 만들었으며 현재(2006년) 2.6.xx 버전이 배포되고 있다. Linux 커널은 .으로 구분된 3자리의 숫자로 구분을 하는데, 첫번째 자리는 major version, 두번째 자리는 minor version, 마지막 자리는 patch version을 나타낸다.

예를 들어 2.6.12 라고 하면, 커널소스와 기능에 있어서 2번의 큰 변화가 있었으며, 2번의 변화가 이루어진 2.0.0에서 6번의 자잘한 변화가 있었음을 의미한다. 12는 2.6.0에서 12번의 패치수준의 변화를 말해준다.

배포판

Linux는 모든 소스코드가 완전히 공개되어 있다. 그러다 보니, 다양한 종류의 배포판들이 존재하게 된다. 이러한 배포판들은 주로 어떤 방식으로 패키지(프로그램)들을 관리하는지에 따라서 구분지어 진다.

수백개의 배포판이 있지만 RedHat(:12), Gentoo(:12), Ubuntu(:12), Fedora(:12) 등의 배포판이 널리 사용되고 있다. 어떤 배포판을 이용해서 리눅스환경을 구축해도 문제는 없겠지만, 입문용으로는 Fedora나 Ubuntu를 추천한다.

이 문서에서는 배포판을 설치하는 방법에 대해서 다루지는 않을 것이다. 시중에 나와 있는 관련 서적이나 각 배포판 커뮤니티의 설치 문서를 참고하기 바란다.

리눅스의 특징

개발자인 필자의 입장에서 리눅스는 또 다른 Unix 운영체제다. 여기에 소개된 리눅스의 특징은 거의 대부분이 Unix의 특징 그대로이다. Linux의 특징을 배우면서 덤으로 Unix의 특징까지 배우게 되니 일석이조라 할 수 있겠다.

리눅스의 특징을 자세히 다루는 것은 이 문서의 범위를 완전히 벗어난다. 여기에서는 개발환경을 이해할 수 있는 수준에서의 최소한의 내용만 다룰 것이다.

유닉스가 모든 리눅스의 특징을 가지고 있으므로, 설명에서는 Unix로 통일하도록 하겠다.

다중 사용자

개인이 사용하는 PC(:12)의 운영체제로 만들어졌던 DOS(:12), Windows(:12)와는 달리 Unix는 처음부터 중대형의 컴퓨터를 제어할 목적으로 만들어진 운영체제다. 그런이유로 처음부터 다중사용자 지원을 고려해서 설계가 되었다.

이런 다중 사용자는 대부분의 경우 물리적으로 컴퓨터에서 멀리 떨어져 있으며, NetWork(:12)를 이용해서 접속 하게 된다. Unix는 접속이 유효한 접속인지 아닌지(불법적인 사용자나 크래커)를 판단하기 위해서 ID:Password 방식의 Login(:12) 시스템을 지원한다.

다중 프로세스

프로세스란 운영체제위에서 주어진일을 하는 프로그램의 실행 이미지다. Unix는 다중의 사용자를 지원하고 있으므로, 동시에 여러개의 프로세스를 지원 할 수 있도록 만들어졌다. A사용자가 웹 브라우진을 하는 동안 B사용자는 DataBase(:12)작업을 하면서 동시에 mp3(:12)를 감상할 수 있다.

높은 이식성

Unix는 운영체제의 80% 이상이 C언어로 만들어졌다. 이는 다른 종류의 컴퓨터에 쉽게 이식할 수 있음을 말한다. Unix는 거의 대부분의 중대형 컴퓨터와 PC/임베디드기기 - Linux -에 설치되어 있다.

단순함

추상적이긴 하지만 유닉스의 단순함은 유닉스의 대표적인 특징이다. 윈도우 사용자가 Unix를 제일 접하면 느끼는게 단순함에서 오는 황당함이다. 도스시절을 보는 것과 같이 컴은 바탕화면에 프롬프트만 깜빡이고 있는걸 보면서 절망을 느낀 사용자도 꽤나 있었을 것이다.

게다가 프로그램역시 너무나 무성의 하기 그지 없다. 아기자기한 아이콘과 다양한 부가기능을 제공하며 마우스 클릭으로 필요한 일을 해결할 수 있는 윈도우와는 달리 Unix의 프로그램은 직접 타이핑을 하고 옵션을 줘서 일을 수행해야 한다. 유닉스 환경에 매우 익숙한 개발자라고 하더라도 파일의 목록을 보여주는 ls의 옵션을 완벽하게 이해하고 사용하는 사람은 아마도 없을 것이다.

그러나 모순되게도 이러한 단순함이 유닉스를 강력하게 만들어준다. 유닉스의 대부분의 기능과 프로그램들은 자기에게 주어진 일만 하며, 복잡한 작업은 철저히 분업화 함으로써 수행을 한다. 텍스트 파일의 내용을 읽어서 Linux가 포함된 라인을 따로 저장하는 일을 하고 싶다고 가정해보자. 간단한 작업같지만 윈도우에서 이러한 일은 원하는 프로그램을 찾아야 하는 지루한 과정을 거쳐야 한다. 유닉스는 아래와 같이 간단하게 해결할 수 있다.
# cat sample.txt | grep "Linux" > Linux.txt
파일의 내용을 출력하는 cat을 이용해서 내용을 읽어오고, 읽어온 내용을 문자열을 비교할 수 있는 기능을 가진 grep에 보내어서 Linux를 포함한 라인을 Linux.txt에 저장하는 방식이다. 철저히 분업화 되어있음을 알 수 있다.

이러한 단순함은 파이프(:12)와 재지향(:12)이라는 기술을 통해서 얻어지는 특징이다. 파이프와 재지향에 대해서는 따로 다루게 될 것이다.

리눅스 환경

리눅스의 환경을 개발에 필요한 최소한의 수준에서 알아보도록 하겠다.

Shell

우리가 컴퓨터를 사용하는데 있어서, 컴퓨터와 운영체제의 복잡한 구성을 이해하고 있을 필요는 없다. 그래야 한다면 컴퓨터는 단지 전문가의 전유물이 되었을 것이다. Shell(:12)은 조개껍질이 내부를 감추는 것처럼 컴퓨터와 운영체제를 내부로 숨긴다. Shell을 이용하는 사용자는 운영체제가 어떻게 명령을 수행하는지 등의 복잡한 것에 신경 쓸필요 없이 shell에 간단히 명령을 내림으로써 필요한 작업을 할 수 있도록 만들어준다.

attachment:shell.gif

shell은 이를테면 운영체제와 사용자를 연결해주는 일을 하는 프로그램이라고 할 수 있다. 여러종류의 게임이 있듯이 shell도 여러종류의 쉘이 있다. ksh, csh, bash, zshell등이 있으며 리눅스 환경에서는 bash(:12)쉘이 가장 널리 사용된다. 쉘 프로그램이라고 부르기도 한다.

쉘은 프롬프트라는 것을 통해서 사용자의 입력을 받아들여서 필요한 일을 수행한다.

attachment:prompt.jpg

윈도우즈에서도 cmd라고 불리우는 쉘을 띄울 수는 있지만, 유닉스의 쉘은 윈도우즈의 쉘과는 다른 차원의 것이다. GUI화면에서 마우스 클릭으로 거의 대부분의 일을 처리하는 윈도우즈와는 달리 유닉스는 거의 모든 작업이 쉘에서 이루어진다. 비록 KDE(:12)와 Gnome(:12)와 같은 데스크탑 환경이 나오긴 했지만, 여전히 많은 유닉스 유저들이 데스크탑환경을 단지 많은 쉘 창을 띄우기 위한 용도로 사용할 뿐이다.

모든 것은 파일이다

유닉스는 모든걸 파일(:12)로 취급한다. 위에 잠깐 언급되었던 것처럼 디렉토리(:12)도 (특수한 형태)의 파일로 취급할 뿐만 아니라, 하드디스크, 이더넷카드, 프린터, 각종 입출력 포트(USB, PS/2, Serial)등 모든 장치까지 파일로 취급한다. 예를 들자면 하드디스크는 /dev/hda1, /dev/hda2, 플로피디스크 드라이브는 /dev/fd0이름의 파일로 관리한다.

윈도우즈유저라면 이러한 환경이 낯설게 느껴지겠지만, 이는 적어도 개발자의 입장에서 봤을 때는 매우 합리적인 구조다. 모든 걸 파일이라는 동일한 객체로 보게 됨으로써, 동일한 프로그래밍 방식을 적용할 수 있기 때문이다. 각각의 장치를 위한 프로토콜은 제외하더라도, 장치에 읽고/쓰는데 있어서 동일한 프로그래밍 기법을 사용할 수 있으므로 개발 시간을 크게 단축시킬 수 있다.

이러한 장치와 관련된 특수한 파일들은 /dev밑에 위치한다.

파이프와 재지향

Pipe(파이프)는 한쪽 객체에서 다른쪽 객체로 어떤 물건을 보내기 위한 통로로 사용된다. 상하수도관이 대표적인 경우가 될것이다. 컨테이너벨트역시 형태는 다르지만 물건을 보내기 위한 통로로 사용된다는 점에서 일종의 파이프라고 할 수 있다.

Unix(:12)역시 객체 사이의 물건을 전달하기 위한 목적으로 파이프를 사용한다. 여기에서 객체는 운영체제(:12)에서 어떤 작업을 수행하는 최소단위인 프로세스가되며, 물건은 일련의 연속된 bit로 이루어진 데이터가 된다.
  +------------+        PIPE       +------------+
  | Process A  | --------||------> | Process B  |
  +------------+                   +------------+

파이프는 유닉스 시스템에서 프로세스간 데이터를 전달하기 위해서 가장널리 필수적으로 사용되는 설비다. 다음은 유닉스에서 파이프를 통해서 작업을 하는 일반적인 예다. 파이프없는 유닉스는 앙꼬 없는 찐빵이라 할 수 있다. 쉘에서는 |를 이용해서 파이프를 이용할 수 있다.
// 프로세스 중에서 vi의 정보를 얻어온다. 
# ps -ef | grep vi 

// file.txt를 읽어서 몇라인으로 구성되어 있는지 확인한다. 
# cat file.txt | wc -l 

// 확장자가 .txt인 모든 파일을 읽어서 "joinc"문자열을 가진 파일을 얻어온다.
# cat *.txt | grep "joinc"

// 프로세스 중에서 root유저가 실행한 vi의 정보를 얻어온다.
# ps -ef | grep vi | grep root

재지향다른 곳으로 향하게 한다라는 뜻을 가지고 있다. 예를 들자면 화면에 출력되는 데이터를 파일이나 프린터등으로 보내기 위한 용도로 사용할 수 있는데, 이 경우 데이터를 파일로 재지향한다. 데이터를 프린터로 재지향 한다. 라고 말한다. 쉘에서는 >를 이용해서 재지향 할 수 있다.
// 프로세스 중에서 root유저가 실행한 vi의 정보를 화면이 아닌  
// rootvi.txt 파일로 재지향한다. 
# ps -ef | grep vi | grep root >  rootvi.txt 

// rootvi.txt 파일의 내용을 프린터로 재지향 한다.
// 프린터가 설정되어 있다면 출력이 될 것이다.
# cat rootvi.txt > lp0

>를 이용해서 재지향 할경우 동일한 이름의 파일이 없다면 새로 생성될 것이다. 만약 동일한 이름의 이름의 파일이 있다면, 덮어써버리게 된다. 덮어쓰지 않고 마지막부터 추가되게 할려면 >>를 이용하면 된다.
// newaddr.txt를 읽어서 addr.txt 파일에 추가한다. 
# cat newaddr.txt >> addr.txt

표준입력,표준출력,표준에러

컴퓨터로 우리가 하는 일은 결국 입력출력 두가지 작업으로 요약될 수 있다. 우리가 입력을 통해서 컴퓨터로 명령을 전달하면, 그 결과는 출력의 형태로 우리에게 전달된다. 입력은 키보드로 출력은 모니터를 통해서 이루어진다.

키보드로 통해서 이루어지는 입력을 표준입력(:12)이라고 하며, 모니터를 통해서 이루어지는 출력을 표준출력(:12)이라고 한다. 그렇다면 표준에러란 무엇인가. 입력은 무조건 하나가 되겠지만, 출력은 한가지 이상이 될 수 있다. 작업을 제대로 마쳤을 경우의 출력결과가 있을 수 있지만 작업을 실패했을 경우의 출력결과가 있을 수도 있기 때문이다. 표준에러는 작업에 실패했다라는 것을 사용자에게 알려주기 위해서 사용한다.

Unix에서는 이러한 입력과 출력까지도 파일로 관리를 한다. 이 파일들은 다음과 같이 입력과 출력에 대응되는 숫자로된 이름을 가지고 있다.
표준입력 0
표준출력 1
표준에러 2
이를 이용해서 재지향을 시킬 때, 표준에러와 표준에러를 따로 저장할 수도 있다.
// 표준출력을 suessvalue.txt로 재지향 한다. 
# ./prog 1> suessvalue.txt

// 표준에러를 error.txt 파일로 저장한다.
# ./prog 2> error.txt
다음과 같은 방법으로 표준에러를 표준출력으로 재지향 시킬 수도 있다.
#./prog 2>&1

계정

리눅스 역시 다른 유닉스들과 마찬가지로 다중사용자 운영체제이다. 이렇다 보니 시스템 자원에 대한 접근권한이 매우 중요해 진다. 예를 들어 특정 유저의 개인 신상정보를 가진 파일은 결코 다른 유저들이 볼 수 있어서는 안될 것이며 shutdown(:12)과 같은 시스템 다운 명령은 특수한 유저(슈퍼유저)만이 제한적으로 실행 가능 해야 할것이다. 아무튼 네트워크장치, 파일, 프로세스, 장치(디스크, CD-ROM, 프린터등)의 모든 시스템 자원에 대해서 사용자 계정수준에서의 접근제어와 관련된 제한이 필요하게 될 것이다. 회사의 직책과 관련된 시스템과 동일하다고 보면 된다. 일반 사원인지, 대리인지, 과장인지, 사장인지에 따라서 접근할수 있는 회사자원의 레벨이 결정되는 것과 마찬가지다. 일반 공지사항이야 전직원이 볼 수 있지만 경영과 관련된 중요 문건은 최고경영진만 볼수 있어야 할것이다.

유저
회사로 치면 사원 개개인이다. 리눅스 시스템 관점에서 보자면 시스템에 접근할 수 있는 최소단위 객체가 된다. 유저는 접근을 위해서 자신의 ID와 패스워드를 가지며, 이외에도 시스템에서의 원할한 활동을 위한 "사용자 홈디렉토리", "사용자 쉘", "포함되는 그룹"과 같은 각종 부가적인 정보들을 가지게 된다. 리눅스에서 유저는 크게 2개로 나누게 된다. 절대적인 권한을 가지는 슈퍼유저와 일반유저 유저다.

슈퍼유저는 보통 ID로 root를 가지며 시스템에서 절대적인 영향력을 행사한다. 시스템의 셧다운, 리부팅, 장치의 제어, 유저제어, 파일제어에 있어서 전혀 제한이 없다. 마음만 먹는다면 rm -rf /로 시스템의 모든 파일을 날려버릴 수도 있는 절대 권한자이다. 워낙에 막강한 권한을 가지고 있기 때문에 운영체제 자체를 파괴해 버리는 어처구니 없는 실수를 할 수도 있다. 해서 몇몇 상용운영체제들은 슈퍼유저라도 파워에 제한을 두기도 한다.

일반 유저는 슈퍼유저를 제외한 나머지 유저를 가리킨다. 일반유저는 슈퍼유저가 정하는 바에 따라서 시스템내에서의 권한과 활동영역에 있어서 제한을 받게 된다.

그룹
회사에서는 인적자원관리의 효율성을 높이기 위해서 개인별로 직책과 직급을 두고 이를 다시 묶어서 부서(팀)를 만들어서 관리한다. 기술개발팀, 경영지원팀, 회계팀, 인사팀등인데, 한명의 직원은 하나 혹은 그 이상의 팀에 소속될 수 있을 것이고 팀의 특징에 따라서 권한이 재조정 될것이다.

회사와 같이 부서(팀)을 만들어서 조직을 효율적으로 만드는것과 같은 구조는 다른 모든 집단에서 (이름만 약간 바꾸어서) 공통적으로 나타나며 운영체제역시 예외없이 이러한 구조를 따른다.

리눅스에서는 이를 그룹이라고 한다. 리눅스에서의 그룹역시 유저자원을 효율적으로 관리하기 위한 장치다. 하나의 유저는 하나이상의 그룹에 포함될 수 있다.

권한
유저와 그룹은 고유의 권한이 있으며, 이러한 권한은 주로 파일에 적용된다. 즉 파일일 읽을수 있는지 (r), 쓸수 있는지 (w), 실행할 수 있는지 (x)에 대해 정의 하는 것으로 이루어진다. 리눅스에서 모든 것은 파일로 다루어지므로 파일에 대해서 권한을 설정한다는 것은 결국 시스템 전체에 대한 권한을 설정하는 것과 동일한 효과를 가진다.

이러한 권한은 유저(User)와 그룹(Group), Other(어디에도 속하지 않은)에 대해서 각각 정의 할 수 있다.
 유저     그룹     Other
+-+-+-+  +-+-+-+  +-+-+-+
|R|W|X|  |R|W|X|  |R|W|X|
+-+-+-+  +-+-+-+  +-+-+-+
 4 2 1    4 2 1    4 2 1
예를 들어 test.txt파일을 유저 yundream에 대해서 읽기/쓰기/실행 권한을 그룹 develop와 Other에는 읽기/쓰기 권한이 부여되어 있다면 ls(:12)결과는 다음과 같을 것이다.
$ ls -al
-rw-r--r--   1 yundream develop     5632 2006-04-19 18:09 uname.c
-rwxr-xr-x   1 yundream develop     5632 2006-04-19 18:09 yundream.txt 
이해하는데 별로 어려움없을 것이다. ls는 권한을 7개의 필터로 나타낸다. 처음 9개 필드가 3개씩 끊어서 유저/그룹/Otehr에 대한 권한을 설정한다. 마지막 필드는 stiky bit와 같은 특수한 정의를 위해서 사용된다.