3. 터미널로 배우는 리눅스 운영체제

김건희·2022년 12월 13일
0

Fundamental

목록 보기
3/7

3-1. 터미널로 배우는 리눅스 운영체제

학습 목표

본 노드는 리눅스 기반 운영체제에 대해 모든 정보를 설명해주는 것보다, 직접 검색해서 이해할 수 있을 정도의 배경과, 어떤 것을 찾아볼지 키워드를 제공하는 것을 목표로 합니다. 따라서 충분히 이해가 되지 않는 부분은 직접 검색을 통해 자료를 찾아가며 보완할 것을 권장합니다.

  • 운영체제의 구성과 커널의 역할에 대해 이해합니다.
  • 터미널과 터미널 에뮬레이터, 셸의 차이점을 이해합니다.
  • 기본적인 리눅스 명령어들을 배우고 사용해 봅니다.
    ❤️: 필수로 꼭 알아두어야 하는 가장 기본적인 명령어입니다.
    👍️: 사용법을 기억해두면 편리한 명령어입니다.
    👌️: 이런 명령어가 있다는 것만 알아두고 필요할 때마다 검색해서 사용하면 충분합니다.
    본 노드는 우분투 20.04를 기반으로 작성되었습니다.

3-2. 떠나자 디지털 월드로!

클라우드 환경을 사용하는 유저라면 이후 실습은 브라우저 우측 하단의 Cloud Shell 열기. 버튼을 누른 후 터미널 창에서 수행하시기 바랍니다.

pwd: 여긴 어디?


[리눅스의 마스코트는 턱스(Tux)라는 이름의 귀여운 펭귄입니다. 물론 늘상 이렇게 얼굴을 찌푸리고 있지는 않습니다.]

Cloud Shell 열기 을 하시면 어두운 화면이 나옵니다.
거기 누구 없어요? echo hello?를 입력하고 엔터를 쳐서 결과를 확인합니다.

$ echo hello?
hello?

❤️ echo: 뒤이어 입력한 내용을 출력합니다.

아무도 없는 것 같습니다. 여기는 어디지? pwd를 입력하고 엔터를 쳐서 결과를 확인합니다.

$ pwd
/aiffel

👍️ pwd: Print Working Directory의 약자(또는 Present Working Directory의 약자)입니다. 현재 내가 위치한 디렉토리 위치를 출력합니다.

/aiffel과 같은 형태의 결과가 표시됩니다. aiffel 폴더 안에 있다는 뜻입니다. 윈도우즈에서는 폴더 구분에 역슬래시(\, 또는 글꼴에 따라 원화 기호 로 출력)를 쓰지만 리눅스에서는 슬래시(/)를 쓰는 것을 알 수 있습니다.

이 위치를 해당 사용자의 홈 디렉토리라고 합니다. 사용자마다 하나씩 주어지며, 윈도우즈의 내 문서 폴더와 비슷하다고 생각하시면 됩니다. 홈 디렉토리를 줄여서 ~로도 표시하는데, 이는 옛날 옛적에 Home 키와 ~ 키가 같은 자판에 있던 시절로부터 전해져 내려온 유구한 전통입니다.

그럼 이제 아까부터 터미널에 떠 있던 저 문구의 뜻을 조금은 알 수 있을 것 같습니다.

root@wtetysocxvx7e6avqwhctccah-776475db6-h2swf:~#
  • cloud shell에서는 $이 아닌 root@wtetysocxvx7e6avqwhctccah-776475db6-h2swf:~# 형태로 표시가 됩니다.
  • @ 앞의 root은 현재 로그인한 사용자명입니다.
  • @ 뒤의 wtetysocxvx7e6avqwhctccah-776475db6-h2swf는 컴퓨터의 이름, 호스트명입니다.
  • : 뒤의 ~는 현재 위치입니다.
  • 마지막 #는 현재 로그인한 사용자가 최고 관리자 계정(root)임을 나타내고 일반 사용자임의 경우에는 $로 표시됩니다.

리눅스는 UNIX라는 운영체제를 본떠 만들어졌는데, 이 UNIX의 철학 중 하나는 "모든 것은 파일이다"라는 점입니다. 윈도우에서는 각종 시스템 설정값이 레지스트리에 들어있지만, 리눅스에서는 설정값 또한 파일이며, 키보드 등의 하드웨어 기기들도 파일로서 접근 가능합니다. 셸 내부에서 나의 위치도 마치 하나의 파일처럼 항상 어떤 폴더 안에 있기 때문에 길을 잃을 염려는 없습니다.

셸 뭐라구요? 우리가 지금 사용하고 있는 것과 같은 프로그램의 종류를 셸(shell) 이라고 하며, 우리는 이 껍데기를 통해 운영체제의 알맹이인 커널(kernel) 과 소통합니다. 셸이 무엇인지에 대해서는 뒤에서 자세히 알아보겠습니다.

ls: 뭐가 있지?

우리는 여기서 어디로 갈 수 있을까요? ls를 입력하여 지금 있는 폴더 안에 어떤 파일/폴더가 있는지 목록을 뽑아봅시다.

$ ls
aiffel  data

❤️ ls: 현재 디렉토리 내의 파일 및 폴더들을 출력합니다.

하지만 세상에 눈에 보이는 것이 전부는 아닙니다. ls 대신 ls --all를 입력해 봅니다.

$ ls --all
.  ..  aiffel  .cache  .conda  data  .jupyter  .local  .wget-hsts

아까는 안 보이던 파일들이 늘어났습니다. 어떻게 된 것일까요?

~가 홈 디렉토리를 가리키는 것처럼, .는 현재 폴더를, ..는 상위 폴더를 가리킵니다.

참고로 리눅스에서 .으로 시작하는 이름을 가진 파일은 숨김 파일입니다. 예를 들어 .bashrc.profile은 셸에 로그인 시 자동으로 불러오는 설정 파일들입니다. 이런 숨김 파일들도 ls 명령어에 --all 인자를 함께 사용하면 모두 표시할 수 있습니다.클라우드 환경에서는 설정 파일이 안보일수 있습니다. ^^

그런데 어떤 명령어가 어떤 인자를 제공하는지는 어떻게 할 수 있을까요?

대부분의 명령어들은 --help라는 인자를 기본으로 제공합니다. ls --help를 입력해 봅시다.

$ ls --help
Usage: ls [OPTION]... [FILE]...
List information about the FILEs (the current directory by default).
Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.

Mandatory arguments to long options are mandatory for short options too.
  -a, --all                  do not ignore entries starting with .
  -A, --almost-all           do not list implied . and ..
      --author               with -l, print the author of each file
  -b, --escape               print C-style escapes for nongraphic characters
      --block-size=SIZE      scale sizes by SIZE before printing them; e.g.,
                               '--block-size=M' prints sizes in units of

내용이 너무 길어서 화면이 넘어갔습니다. 지금 화면에서는 마우스도 쓸 수 없는데 어떡하냐구요? Ctrl+Shift+↑/↓으로 한줄씩 위/아래로 스크롤하거나, Shift+PageUp/PageDown으로 한 페이지씩 위/아래로 스크롤 할 수 있습니다.

-B, --ignore-backups       do not list implied entries ending with ~
  -c                         with -lt: sort by, and show, ctime (time of last
                               modification of file status information);
                               with -l: show ctime and sort by name;
                               otherwise: sort by ctime, newest first
  -C                         list entries by columns
      --color[=WHEN]         colorize the output; WHEN can be 'always' (default
                               if omitted), 'auto', or 'never'; more info below
  -d, --directory            list directories themselves, not their contents
  -D, --dired                generate output designed for Emacs' dired mode
  -f                         do not sort, enable -aU, disable -ls --color
  -F, --classify             append indicator (one of */=>@|) to entries

--all-a로 줄여서 쓸 수도 있다는 점을 알았습니다. 추가로 다음 인자들도 눈여겨보면 좋습니다.

  • -l: 각 파일 및 폴더의 권한, 소유자, 크기, 수정일시 등 자세한 정보를 출력합니다.
  • -h: 파일 크기를 바이트 수 대신 사람이 알아볼 수 있는 단위(1K, 234M, 2G 등)로 표시합니다.
  • -t: 파일 수정시간 순으로 정렬해서 출력합니다. 최신 파일이 위쪽으로 표시됩니다.
  • -r: 정렬 순서를 뒤집어 출력합니다. -rt의 형태로 쓰면 최신 파일이 아래쪽으로 표시되어 유용할 때가 있습니다.

한 글자 인자를 여럿 쓸 때에는 서로 붙여 쓸 수 있습니다. 즉, ls -l -a -hls -lah로 쓸 수 있습니다.

$ ls -lah
total 32K
drwxr-xr-x 1 root root 4.0K Jun  7 05:10 .
drwxr-xr-x 1 root root 4.0K Jun  7 05:10 ..
drwxrwxrwx 2 root root    0 Jun  2 02:45 aiffel
drwxr-xr-x 1 root root 4.0K Apr 19 09:30 .cache
drwxrwsr-x 2 root root 4.0K Apr 19 09:30 .conda
drwxr-xr-x 2 root root 4.0K Jun  4 03:42 data
drwx------ 1 root root 4.0K Apr 19 09:23 .jupyter
drwxr-xr-x 3 root root 4.0K Jun  7 05:10 .local
-rw-r--r-- 1 root root  170 Apr 19 09:28 .wget-hsts

(Tip) ls -alrt 가 유용할 때가 많습니다.


ls 뒤에 폴더명을 넣어서 해당 폴더 안을 볼 수도 있습니다. ls --all aiffel를 입력해 aiffel 폴더 안에 어떤 파일들이 있는지 살펴봅니다.

$ ls --all aiffel
.  .. 

aiffel 폴더 자체와 그 상위 폴더인 홈 디렉토리를 각각 가리키는 .와 ..만 나옵니다. 무슨 뜻일까요? 제가 게을러서 공부를 안하기 때문에 aiffel 폴더 안에 아무것도 없다는 뜻입니다. 여러분은 지금쯤 aiffel 디렉토리 안에 멋진 프로젝트 결과물들이 많이 있으시겠죠?

cd: 움직여보자

리눅스에서 모든 것은 파일이고, 나도 파일처럼 항상 어느 폴더 안에 들어있다는 사실을 위에서 배웠습니다. 그럼 내가 다른 폴더로 이동하려면 어떻게 해야할까요? 내가 들어있는 디렉토리를 바꾸면 됩니다. cd aiffel를 입력해 aiffel 폴더 안으로 이동해 봅시다.

$ cd aiffel
root@wtetysocxvx7e6avqwhctccah-776475db6-h2swf:~/aiffel

❤️ cd: Change Directory의 약자로, 뒤에 따라오는 폴더로 내가 있는 셸의 현재 위치를 이동시킵니다.

커서 앞의 ~~/aiffel로 바뀌었습니다. 여기서 pwd를 해보면?

$ pwd
/aiffel/aiffel

여기서 다시 상위 폴더로 이동하려면? ..이 상위 폴더를 가리킨다고 했으니, cd ..를 입력한 뒤 이어서 pwd를 해 봅니다.

$ cd ..
$ pwd
/aiffel

여기서 ..aiffel에서처럼 명령을 입력하는 시점에 내가 현재 있는 디렉토리에 영향을 받는 위치 표시 방식을 상대 경로라고 합니다. 반면에 /home/june/aiffel와 같이 어디서 입력하든 똑같은 곳을 가리키도록 위치 전체를 적어주는 것을 절대 경로라고 합니다.

뒤에 위치 없이 그냥 cd만 입력하면 어디로 갈까요?

그럼 이 세상의 끝은 어디일까요? 계속 한번 위로 올라가봅시다.

$ cd ..
$ cd ..
$ pwd
/

/에 도달한 이후 더 이상 상위 폴더로 올라가지지 않습니다. 여기가 바로 세상의 끝입니다.

세상의 끝에는 무엇이 있을까요?

$ ls
aiffel  boot  etc   lib    media  opt   root  sbin  sys  usr  workspace
bin     dev   home  lib64  mnt    proc  run   srv   tmp  var

일부 주요 폴더들의 용도 및 내용물은 다음과 같습니다. 굳이 기억할 필요는 없고, 이런 것들이 있다는 것만 알고 넘어갑시다.

  • /home: 사용자별 홈 디렉토리들이 있는 곳
  • /root: 최고 관리자 계정의 홈 디렉토리
  • /mnt: 저장장치(HDD, SSD)가 붙는 위치
  • /media: 이동식 미디어(USB 드라이브)가 붙는 위치
  • /tmp: 재부팅 시 삭제될 임시 파일들을 저장하는 폴더
  • /dev: 컴퓨터에 연결된 하드웨어 및 가상 기기(device)들을 가리키는 파일들
  • /proc: 현재 실행 중인 프로세스들을 가리키는 파일들
  • /etc: 각종 설정 파일들
  • /bin: 실행 가능한 프로그램(binary)들
  • /sbin: 시스템 관리용 프로그램들
  • /usr: 다중 사용자 모드에서 사용 가능한 파일 및 프로그램들 (root 계정만 있는 단일 사용자 모드에서는 사용 불가)
  • /var: 캐시, 로그 등 시스템 구동 간 계속 내용이 바뀌는 파일들
    한번 어디로 들어가 볼까요? 최고 관리자 계정이 탐이 납니다.
$ cd root
$ ls -l
total 500
-rw-r--r-- 1 root root 506002 Apr 19 08:55 1.6.2.zip
drwxr-sr-x 1 root root   4096 Apr 19 08:55 ttyd-1.6.2

3-3. 운영체제 일반 개론

(1)운영체제란?

잠시 안도의 숨을 돌리면서, 리눅스를 넘어 일반적인 운영체제에 대해 이야기해보겠습니다. 운영체제란 컴퓨터의 다양한 하드웨어 장치들과 더불어 소프트웨어를 관리하는 시스템을 일컫습니다.

막연하실 것 같아 이런 예를 들어 보겠습니다.
커다란 프랑스 귀족 저택에 요리사가 3명, 정원사 5명, 청소부가 10명이나 있다고 합시다. 심지어 이 하인들은 출신국가나 언어도 제각기 달라서 어떤 요리사는 영어를, 어떤 청소부는 독일어를, 어떤 정원사는 중국어를 쓰기도 한다고 합시다. 이 저택의 집주인이 이 많은 하인들에게 일을 직접 시키려면 얼마나 힘들겠습니까? 적절하게 필요 자원을 배분해서 일을 시키는 것만으로도 바쁜데, 그 수많은 하인들의 언어와 성격까지 맞추어 일을 시킨다는 것은 보통 일이 아니겠죠?
이때, 전세계 모든 언어를 마스터한 스마트한 집사가 하나 나타났다고 생각해 봅시다. 이제 이 귀족은 굳이 하인들을 직접 만날 필요가 없습니다. 그냥 스마트한 집사에게 모든 것을 시키면 됩니다. 설령 요리사가 도중 아프리카인으로 교체된다고 해도 귀족 집주인은 신경쓸 필요가 없습니다. 달라지는 부분에 대해서는 집사가 다 알아서 해줄 테니까요.

비유해서 생각하면 운영체제는 컴퓨터라는 대저택을 관리하는 집사와 같은 존재로 볼 수 있습니다. 집주인(최고관리자)의 권한을 위임받아 요리사, 정원사, 청소부 등 각각의 보조 인원(어플리케이션)들에게 재산(연산 자원)을 적절히 분배하여 운영하고, 서로 권한을 침범할 수 없도록 관리하는 역할을 맡습니다.

우리가 지금 보고 있는 것은 운영체제들 중 리눅스 계열의 우분투(Ubuntu)라는 운영체제입니다. 조금 더 친숙한 운영체제로는 마이크소프트의 윈도우즈나, 애플의 맥 OS, iOS, 구글의 Android, ChromeOS 등이 있습니다.

그런데 위 그림에서 도대체 어디가 운영체제냐구요? 위 그림에서 CPU, Memory, SDD 등 각종 디바이스를 통합관리하면서 그 연산자원을 수많은 어플리케이션들에게 분배하는 자리에 있는 것은 바로 커널(Kernel)이라는 것입니다. 운영체제=커널이라고 할수는 없겠지만 커널은 보안, 자원관리, 디바이스 인터페이스 추상화 등 바로 대저택의 집사와 같은 역할을 하는 운영체제의 가장 핵심적인 구성요소입니다.

(2)커널

운영체제의 내부는 알맹이인 커널(kernel)과 껍데기인 셸(shell)로 이루어져 있습니다. 우분투의 커널은 리눅스이고, 마이크로소프트 윈도우(Windows)의 경우 2000 이후의 버전은 Windows NT라는 커널을 사용하며, 맥 OS(macOS)의 경우에는 XNU(XNU is Not Unix의 약자)라는 커널을 사용합니다.

Q. 그래서 버전이 8이라는 거야 6.3이라는 거야? A. 전체 운영체제의 버전이 8이고, 커널의 버전이 6.3이라는 뜻입니다.

윈도우를 제외한 운영체제들은 사실상 서로 사촌지간이라고 볼 수 있는데, 여기에는 약간의 역사가 있습니다. 태초에 유닉스(Unix)라는 상용 운영체제(겸 해당 운영체제를 위한 커널)가 있었습니다. 이를 기반으로 미국 UC 버클리에서 개발한 BSD 운영체제가 나오자, 미국 카네기 멜론 대학교에서 BSD를 위해 Mach 커널을 개발합니다. 1985년 애플에서 쫓겨났던 스티브 잡스가 창업한 NeXT에서는 이 Mach 커널을 사용해 XNU라는 커널을 만듭니다. 이후 NeXT가 (스티브 잡스와 함께) 애플에 흡수되면서 XNU는 맥 OS, iOS (및 iPadOS, tvOS, watchOS..) 운영체제에서 커널로 사용되게 됩니다.

리눅스 커널 또한 유닉스와 관련이 깊은데, 1991년 핀란드에서 당시 컴퓨터 공학과 학생 리누스 토발즈(Linus Torvalds)가 유닉스의 무료 및 공개 버전을 지향하여 만든 것이 리눅스입니다. 여기서 명심할 점은 리눅스가 그 자체로 운영체제가 아니라, 운영체제를 위한 커널이라는 사실인데, 우리가 흔히 리눅스 운영체제라 부르는 것들은 사실 이 리눅스를 커널로써 사용하는 운영체제들을 가리키며, 우분투나 Android, ChromeOS 말고도 Debian, CentOS, Red Hat Enterprise Linux 등 다양한 종류가 있습니다.

즉, 맥 OS의 XNU 커널과 우분투의 리눅스 커널은 역사적 배경 때문에 모두 유닉스와 유사하며, 유닉스 표준(POSIX)과 일부 호환성이 제공됩니다. 이런 유사성은 두 운영체제 모두 동일하게 bash를 기본 셸로 제공하는 점에서도 찾아볼 수 있습니다.

bash가 뭐냐구요? 궁금하시면 cloud shell 열기를 누른 후 echo $SHELL 이라고 입력해 보세요.

(3) 셸(shell)

셸은 말 그대로 눈에 보이는 운영체제의 껍데기인데, 그래픽 기반의 GUI(Graphical User Interface) 셸과 텍스트 기반의 CLI(Command Line Interface) 셸로 구분할 수 있습니다.

GUI 셸의 경우, 윈도우에는 우리에게 친숙한 시작 버튼을 포함하는 셸을 Windows shell이 라 부르고, 맥 OS의 경우는 Aqua라는 이름을 갖고 있습니다. 리눅스 계열 운영체제는 GNOME, Unity(동명의 게임 엔진과는 별도의 프로그램) 등이 있지만, 단독으로 동작하기보다 보통 Xorg 등 다른 종류의 프로그램들과 함께 사용됩니다.

CLI 셸로는 윈도우 운영체제의 cmd.exe와 PowerShell이 있고, 우분투 및 맥 OS에서는 CLI 셸로서 기본으로 sh와 여기에 몇 가지 편의기능을 덧붙인 bash가 설치되어 있습니다. 이 외에도 csh, fish, zsh 등 다양한 CLI 셸을 직접 설치하여 사용할 수 있습니다. 또한 zsh처럼 테마 및 플러그인을 지원하는 셸의 경우 모양과 편의기능을 입맛에 따라 꾸밀 수 있습니다.

[zsh와 함께 사용할 수 있는 pure 테마 (https://github.com/sindresorhus/pure)]

(4) 프로세스와 스레드

프로그램 은 컴퓨터가 수행할 작업을 기록해놓은 것을 뜻합니다. 프로그램이 실제로 작업으로서 수행될 때 운영체제는 이를 프로세스(process) 라는 단위로 관리합니다. 즉, 운영체제는 프로세스 단위로 메모리와 CPU 연산 등 컴퓨팅 자원을 분배합니다.

  • 메모리 관리 : 운영체제는 프로세스가 컴퓨터의 전체 메모리 어디든지 쓸 수 있도록 하는 것이 아니라 가상 메모리(virtual memory)로서 일부만 떼어서 제공해줌으로써, 다른 프로세스의 메모리 또는 운영체제 자체가 사용하고 있는 커널 메모리를 훔쳐볼 수 없도록 합니다. 이것을 운영체제의 중요한 보안 기제 중 하나인 프로세스 격리(process isolation)라고 부르며, 때문에 프로세스들이 서로 소통하기 위해서는 별도로 허용된 프로세스 간 통신 (Inter-Process Communication, IPC) 기법들을 사용해야 합니다.

  • CPU 자원 관리 : 메모리는 주소로서 프로세스에게 제공되지만, CPU 연산의 경우 코어 단위로 프로세스에 제공됩니다. 프로세스는 스레드(thread) 라는 단위로 코어를 하나씩 사용할 수가 있는데, 프로세스가 하나 시작되면 기본적으로 하나의 스레드를 가지고 시작하지만, 개발자는 프로그램이 더 많은 스레드를 사용하도록 설계하여 다중 CPU 코어의 이점을 극대화할 수 있습니다.

프로세스는 운영체제가 메모리를 할당하는 작업단위라면, 스레드는 프로세스가 할당받은 메모리를 활용하는 실행단위입니다.
하나의 프로그램 안에서 여러개의 프로세스를 활용하는 것을 멀티프로세싱(Multiprocessing) , 하나의 프로세스 안에서 여러개의 스레드를 활용하는 것을 멀티스레딩(Multithreading) 이라고 합니다.

3-4. 리눅스 기반 운영체제

(1) 터미널

위에서는 일반적인 운영체제에 공통적인 내용을 다루었지만, 이제부터는 리눅스 기반 운영체제에 조금 더 특화된 내용을 살펴보겠습니다.

우분투에서 Cloud shell 열기를 눌러보면 아까 본 텍스트 화면이 들어있는, 흔히 터미널 또는 콘솔이라고도 부르는 창이 열립니다. 이 창 내부에서 텍스트로 조작하는 환경은 위에서 배웠듯이 CLI 셸입니다. 이 창을 여는 프로그램은 엄밀히 말하면 터미널이 아니라, 정확히는 그래픽 환경에서 터미널을 모사하는 터미널 에뮬레이터입니다. 그렇다면 진짜 터미널이란 무엇을 가리키는 걸까요?

터미널이라는 이름은 개인용 컴퓨터(PC)가 등장하기 전의 시절, 실제 연산을 담당하는 크고 비싼 메인프레임 컴퓨터와는 별도로, 입출력만 담당하는 CRT 모니터와 키보드로 구성된 말단(=terminal)의 기기에서 유래한 명칭입니다. 여러 대의 터미널을 한 대의 메인프레임에 연결해 여러 사용자끼리 나눠 사용하는 것도 가능했으며, 원격으로 타이핑을 한다는 의미에서 teletype이라는 명칭으로도 불렸습니다.

시대가 흘렀지만 teletype은 운영체제 안에 흔적이 남아있습니다. /dev(device, 장치) 폴더 안에는 tty(teletype)로 시작하는 여러 대의 소프트웨어 터미널이 있습니다. 물론 시리얼 포트를 통해 실제 하드웨어 터미널과 연결할 수 있는 ttyS도 함께 남아있습니다.

$ ls /dev
core  full    null     nvidiactl   nvidia-uvm-tools  pts     shm     stdin   termination-log  urandom
fd    mqueue  nvidia0  nvidia-uvm  ptmx              random  stderr  stdout  tty              zero

우분투에서는 18.04부터 로그인한 사용자의 그래픽 환경을 2번 터미널에 붙여두기 때문에, 우리는 CLI 셸(tty3)에서 무사히 GUI 셸(tty2)으로 귀환할 수 있었습니다. 즉, 터미널이란 컴퓨터에 정보를 입력하고 출력하는 소프트웨어 및 하드웨어로써의 장치이며, 지금도 우리는 하나의 터미널(tty2)이라는 창구를 통해 컴퓨터 안의 세상을 그래픽으로써 들여다보고 있는 것입니다. 아래 영상의 장치도 터미널이라 부르기에 충분합니다.

(2) 프로세스 관리와 시스템 콜

이제 터미널과 터미널 에뮬레이터의 차이를 배웠으니, 여러분의 터미널 에뮬레이터를 열고 몇 가지 명령어를 새로 배워봅시다.

주피터 노트북이 돌아가고 있다면 새로운 탭 또는 창으로 새로운 터미널 세션을 시작해 주세요.

우선 ps -e를 입력하여 현재 실행 중인 프로세스들을 확인합니다. 윈도우 작업 관리자의 첫 화면과 같다고 생각하시면 됩니다.

👍️ ps: 현재 터미널과 관련된 프로세스 목록을 출력합니다.
👍️ ps -ef: 모든 터미널에서 현재 실행중인 프로세스 목록 및 부가정보를 출력합니다.

$ ps -ef
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 05:10          ?        00:00:00 /bin/sh -c jupyter notebook  --NotebookApp.token=$DEFAULT_JU
root          6      1  0 05:10          ?        00:00:07 /opt/conda/bin/python /opt/conda/bin/jupyter-notebook --Note
root          7      1  0 05:10          ?        00:00:00 ttyd -p 8887 /bin/bash
root         10      7  0 05:50     pts/0    00:00:00 /bin/bash
root         13      7  0 05:53     pts/1    00:00:00 /bin/bash
root         17      7  0 05:55     pts/2    00:00:00 /bin/bash
root         20      7  0 06:02     pts/3    00:00:00 /bin/bash
root         66      7  0 07:23     pts/4    00:00:00 /bin/bash
root         69     66  0 07:47    pts/4    00:00:00 ps -ef

PID는 process ID 번호이고, TTY는 해당 프로세스가 붙어있는 teletype(터미널)입니다. 0번 가상 터미널(pts, pseudo teletype slave)에 우리가 방금 실행한 ps 명령어와, 해당 명령어를 실행한 셸 bash가 떠있습니다. TTY 칸에 ?가 표시된 프로세스들은 터미널에 부착되지 않은 프로세스들입니다.

자, 이제 한번 프로세스를 하나 죽여봅시다. GUI 셸의 핵심인 Xorg가 만만해 보입니다. 조금 갑작스럽지만 컴퓨터는 원래 망가트리면서 배워야 제맛입니다. 물론 실제로 망가뜨리진 않겠지만, 열려있던 창이 모두 종료될 테니 작업 중이던 내용을 모두 저장한 다음, 위에서 확인한 /usr/bin/Xorg 프로세스의 번호를 넣어 sudo kill -s KILL [PPID]를 입력합니다. [PPID] 부분에 여러분의 컴퓨터에서 실제로 출력한 숫자를 집어넣으세요. 여러분의 터미널에서 나오는 프로세스 번호는 GUI가 켜질 때마다 다르게 부여될 수 있으니 아래와 같이 꼭 직접 확인하세요.

$ ps -ef | grep Xorg
root         71     66  0 07:54 pts/4    00:00:00 grep Xorg

👍️ grep: 입력으로 전달된 내용에서 특정 문자열을 포함한 라인만 선택해서 출력합니다. 파이프(|)를 통해 다른 명령문 실행결과와 결합해서 사용할 때 특히 유용합니다.

❤️ sudo: 이어지는 명령을 최고 관리자 권한으로 실행합니다.

👍️ kill: PID에 해당하는 프로세스에 시그널을 보냅니다.

$  sudo kill -s KILL 66

Xorg가 죽으면서 화면이 잠시 꺼졌다가, 자동으로 재시작하면서 다시 로그인 화면으로 돌아올 겁니다. (혹시 응답이 없다면 그냥 컴퓨터를 껐다 켜세요. 아마 괜찮을 겁니다.👻) 참고로 나중에 언젠가 컴퓨터가 돌아가는데 화면이 얼었을 때, 이런 식으로 3번 터미널의 CLI로 전환해서 GUI를 죽이고 다시 2번 터미널의 GUI로 돌아오는 방법으로 재부팅 없이 해결할 수 있습니다. 물론 GUI 상에서 돌아가고 있던 프로그램들의 정보는 날아갈 수 있으니 주의해야 합니다.

그럼 Xorg 프로세스의 종료는 어떤 방식으로 이뤄진 걸까요? 프로세스 관리는 운영체제의 고유 권한이기 때문에, 우리는 커널의 도움이 필요합니다. 우리가 CLI 셸에 kill 명령어를 입력하는 순간, 셸의 프로세스는 커널에게 이 명령을 전달하고, 커널은 권한 등을 확인한 후에 이를 수행합니다. 이렇게 프로세스가 커널에게 요청을 전달하는 기능을 시스템 콜(system call) 이라고 합니다. 즉, 시스템 콜은 운영체제의 커널이 프로그램에 제공하는 인터페이스이며, 프로세스가 직접 할 수 없는 프로세스 제어(kill 등), 파일 조작(폴더 생성 mkdir, 파일 읽기 read 등), 장치 및 자원 관리, 네트워크 통신 등을 가능케 합니다. 반대로 보면, 각 프로세스는 커널을 통하지 않고서는 파일이나 장치, 또는 다른 프로세스에 간섭할 수 없다는 뜻이 됩니다.

참고로 kill은 그 자체로 프로세스를 죽이는 명령이 아니라, 프로세스에 신호를 보내는 명령어입니다. 강제종료하는 KILL 외에도, 프로그램 실행 중에 Ctrl+C를 누르면 전달되는 INT (interrupt) 신호나, 프로세스를 종료하기 전에 해당 프로세스에게 해명할 기회를 주는 TERM (terminate) 신호도 있습니다.

(3) 프로그램과 환경변수

여태까지 셸에서 여러 명령어를 실행해 보았지만, 사실 우리가 실행했던 명령어들의 진짜 정체는 두 가지로 구분할 수 있습니다. 1) 실제 프로그램과 2) 셸에서 제공하는 셸 명령어입니다. which 명령어를 사용해서 그 정체를 한번 밝혀봅시다.

👌️ which: 명령어의 전체 경로를 출력합니다.

$ which ls
/bin/ls
$ which cd

짜잔! ls/bin 디렉토리에 설치된 ls라는 프로그램이고, cd는 프로그램이 아니라 셸에서 제공하는 명령어였기에 아무 결과도 출력되지 않습니다. 우리가 사용하는 셸은 bash였죠? 셸도 프로그램일 테니 한번 경로를 확인해 봅시다.

$ which bash
/bin/bash

즉, 우리가 셸에 명령어를 입력하면 셸은 일단 셸 내에서 정의된 명령인지 확인합니다. 만약 셸에 정의된 명령 중 있다면, 그대로 명령을 실행합니다. 셸에 정의된 명령이 아니라면, 설치된 프로그램 중에서 해당 이름을 가진 프로그램이 있는지 확인하여 실행합니다. 그럼 해당 이름을 가진 프로그램이 실제로 설치되어 있는지는 어디서 확인할까요? echo $PATH라고 입력하여 한번 물어봅시다.

$ echo $PATH
/opt/conda/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

무언가 나왔습니다. 일단 우리가 입력한 명령을 먼저 이해해 보겠습니다. echo는 뒤에 입력된 내용을 출력하라는 명령어였는데, 뒤의 $PATH는 무엇일까요?

셸에서 단어 앞에 가 붙으면 **환경 변수(environment variable)** 를 의미합니다. 파이썬의 변수처럼, 환경 변수는 운영체제가 프로세스 단위로 사용하는 변수입니다. 즉, 우리가 echo $PATH는 PATH라는 이름의 환경 변수()의 값을 출력(echo)하라는 뜻입니다.

PATH 환경 변수는 셸이 프로그램을 실행할 때 참조할 경로들을 나타냅니다. 값을 보면 디렉토리 여러 개가 :로 구분되어 있는 것을 알 수 있는데, 만약 동일한 이름의 프로그램이 여러 디렉토리에 설치되어 있다면, PATH 내 순서 상 앞에 있는 디렉토리의 프로그램을 실행합니다. 아나콘다(Anaconda)를 설치했다면, 우분투에 기본으로 설치된 파이썬 대신 아나콘다가 설치한 파이썬을 사용하도록 PATH의 값이 변경되어 있을 겁니다. 마찬가지로 which python을 통해 확인해볼 수 있습니다.

참고로 PATH 환경 변수의 기본값은 사용자가 로그인할 때 운영체제가 자동으로 정의하지만, 사용자가 직접 수정할 수도 있습니다. 셸 명령어인 export 명령어를 통해 PATH의 앞에 /aiffel 디렉토리를 추가해 봅시다.

👌️ export: 셸 변수나 함수를 현재 환경으로 내보냅니다.

$ echo $PATH
$ export PATH=/aiffel:$PATH
$ echo $PATH

이렇게 PATH환경변수에 디렉토리 경로를 추가하면 셸이 특정 프로그램을 실행할때 참조할 수 있게 되는 것입니다

또한 env 명령어로 현재 설정된 환경변수들을 모두 출력할 수 있습니다.

👌️ env: 명령어가 제공된다면 해당 명령어를 새로운 환경에서 실행합니다. 명령어가 제공되지 않은 경우 현재 환경의 정보를 출력합니다.

$ env
CUDNN_VERSION=8.0.5.39
WTETYSOCXVX7E6AVQWHCTCCAH_PORT_8887_TCP_ADDR=10.0.253.249
LC_ALL=en_US.UTF-8
WTETYSOCXVX7E6AVQWHCTCCAH_PORT_8888_TCP_PROTO=tcp
LD_LIBRARY_PATH=/usr/local/nvidia/lib:/usr/local/nvidia/lib64
WTETYSOCXVX7E6AVQWHCTCCAH_SERVICE_PORT=8888
LANG=en_US.UTF-8
HOSTNAME=wtetysocxvx7e6avqwhctccah-776475db6-h2swf
CONDA_DIR=/opt/conda
CONDA_VERSION=4.9.2
NVIDIA_VISIBLE_DEVICES=GPU-69bafdf7-9469-6565-605e-81ec2a4871ed
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.0.0.1
NCCL_VERSION=2.8.4
TF_FORCE_GPU_ALLOW_GROWTH=true
KUBERNETES_PORT=tcp://10.0.0.1:443
PWD=/aiffel
HOME=/aiffel
....

우리가 /bin 디렉토리 안의 프로그램 bash를 현재 셸(SHELL)로서 사용한다는 내용도 나와있네요.

(4) 패키지 관리자

그럼 리눅스 기반 운영체제, 특히 우분투에서 새로운 프로그램을 설치하거나 기존에 설치된 프로그램을 업데이트 하려면 어떻게 할까요? 인터넷에서 설치 파일을 다운로드 받아 직접 실행할 수도 있지만, 우분투 운영체제는 공식적으로 APT(Advanced Packaging Tool)라는 패키지 관리자(package manager) 를 제공합니다.

패키지 관리자란 공인 저장소에서 프로그램과 라이브러리(다른 프로그램들이 참조하여 사용할 수 있는 코드)를 패키지 단위로 설치하고 관리할 수 있도록 하는 프로그램입니다. 내가 작성한 유용한 코드를 잘 패키징해 모두가 볼 수 있는 곳에 올려둔다면, 다른 사람들도 손쉽게 코드를 다운 받아 사용할 수 있겠지요.

우분투에는 APT말고도 Snap이라는 비교적 새로운 프로그램도 있으며, CentOS의 YUM(Yellowdog Updater Modified), Red Hat 계열의 RPM(Red Hat Package Manager) 등 각 리눅스 계열 운영체제는 다양한 기본 패키지 관리자를 제공합니다. 운영체제 상 패키지 관리자 외에도, 파이썬의 PIP(Python Package Installer) 등 프로그래밍 언어상 제공되는 경우도 있습니다.

이제 APT로 우분투에 htop이라는 프로그램을 설치해 보겠습니다. htop은 CPU 및 메모리 사용량을 시각화하고, 프로세스 별 CPU 사용량을 표시해 주는 프로그램입니다.

❤️ apt-get: APT 패키지 관리자를 통해 공인 저장소에서 패키지를 가져다 설치하거나 제거합니다.

우선 등록된 공인 저장소에 있는 패키지 목록을 최신 버전으로 가져옵니다.

$ sudo apt-get update
Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]
Hit:2 http://archive.ubuntu.com/ubuntu bionic InRelease                                
Get:3 http://security.ubuntu.com/ubuntu bionic-security/multiverse amd64 Packages [24.7 kB]
Get:4 http://security.ubuntu.com/ubuntu bionic-security/universe amd64 Packages [1,414 kB]     
Get:5 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB]          
Get:6 http://security.ubuntu.com/ubuntu bionic-security/restricted amd64 Packages [450 kB]     
Get:7 http://security.ubuntu.com/ubuntu bionic-security/main amd64 Packages [2,184 kB]                       
Get:8 http://archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB]                                  
Get:9 http://archive.ubuntu.com/ubuntu bionic-updates/restricted amd64 Packages [480 kB]
Get:10 http://archive.ubuntu.com/ubuntu bionic-updates/universe amd64 Packages [2,184 kB]
Get:11 http://archive.ubuntu.com/ubuntu bionic-updates/multiverse amd64 Packages [33.5 kB]
Get:12 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 Packages [2,616 kB]
Fetched 9,639 kB in 1s (6,596 kB/s)                          
Reading package lists... Done

이제 설치를 진행합니다. 패키지 목록을 읽고, 해당 패키지가 의존하는 다른 패키지들이 있는지 등을 자동으로 확인한 뒤, 설치를 진행합니다.

$ sudo apt-get install htop

설치가 완료되면 바로 실행해 봅시다. htop을 종료하려면 q를 누르면 됩니다.

$ htop

삭제는 설치만큼 쉽습니다. apt-get 뒤에 install 대신 remove를 넣어서 프로그램만을 제거하거나, purge를 넣어 해당 프로그램의 설정 파일까지 모두 삭제시킬 수 있습니다. 만약 중간에 확인([Y/n])을 물으면 y를 누르고 엔터를 쳐서 제거를 승인합니다.

$ sudo apt-get remove htop
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following packages will be REMOVED:
  htop
0 upgraded, 0 newly installed, 1 to remove and 44 not upgraded.
After this operation, 221 kB disk space will be freed.
Do you want to continue? [Y/n] y

(5) 사용자와 권한

sudo 명령어


여태까지 sudo라는 명령어를 계속 사용해왔는데, 이제 그 뜻을 한번 자세히 알아볼 때가 되었습니다.

하나의 메인프레임 컴퓨터에 여러 개의 터미널을 붙여 사용할 수 있게 했던 것처럼, 한 대의 컴퓨터를 여러 사람이 함께 사용하는 것은 운영체제의 초기 역사부터 일반적인 사용법이었습니다. 이 때문에 사용자(user)를 구분하고 권한을 나누는 일이 중요했으며, 그 개념은 한 사람이 한 대의 컴퓨터를 사용하는 개인용 컴퓨터(personal computer, PC) 시대의 운영체제에도 그대로 남았습니다. 특히 유닉스 계열 운영체제들은 개인용 컴퓨터보다 서버용 또는 기타 산업용으로 쓰이는 경우가 잦기에, 다른 운영체제보다 사용자와 권한의 개념을 훨씬 더 자주 마주치게 됩니다.

유닉스 계열 운영체제에서 모든 권한은 사용자를 기준으로 인증합니다. 운영체제에서 어떤 작업을 실행하기 위해서는 어떤 사용자 이름으로 실행할지 미리 정해져 있어야 한다는 뜻입니다.

ps -ef 명령어를 사용하면 프로세스마다 누구의 권한으로 실행되는지(UID, User ID) 확인할 수 있습니다. 프로세스는 현재 사용자가 가진 범위만큼의 권한을 가집니다. 우리가 위에서 cd /root로 최고 관리자의 디렉토리에 접근하려고 했을 때처럼, 해당 사용자의 권한을 넘어서는 작업을 요청하면 운영체제의 커널이 이를 거부합니다.

보통 우리가 사용하는 사용자 계정은 운영체제를 설치할 때 최초로 생성한 계정입니다. 개인용 컴퓨터에서는 이 사용자가 해당 컴퓨터를 사용할 주된 사람일 것입니다. 하지만 리눅스 기반 운영체제, 윈도우, 맥 OS 모두 공통적으로, 해당 사용자 계정에게 운영체제에 대한 모든 권한이 주어지지는 않습니다. 보안 및 시스템 안정성을 위해 완전한 권한은 운영체제에 기본으로 설정된 최고 관리자(superuser) 계정만이 가지고 있으며, 윈도우에서는 이 계정을 Administrator이라고 부르고, 유닉스 계열 운영체제에서는 root라는 아이디를 가지고 있습니다.

우리가 직접 생성한 사용자 계정은 일반 사용자 계정입니다. 이 때문에 운영체제 자체에 영향을 주는 일(커널 권한이 필요한 프로그램의 설치나 실행 등)은 최고 관리자 권한을 빌려야 합니다. 윈도우에서 무언가를 설치할 때 가끔 보게 되는 "관리자 권한으로 실행" 경고창이나, 유닉스 계열 운영체제에서 사용하는 sudo(superuser do) 명령어가 바로 이 역할을 하며, 일반 사용자가 잠시 최고 관리자(또는 다른 사용자) 권한으로 행동할 수 있게 해줍니다. 매번 확인해야 하는 것이 번거로울 수 있지만, 한 번 더 확인함으로써 실수를 방지할 기회를 준다는 것 외에도 모든 권한이 아닌 일부 권한만 허용할 수 있는 등 다양한 보안상의 이점이 있습니다.

사용자 그룹

사용자들이 여러 명 있을 때, 쉽게 묶어서 관리하는 개념이 바로 그룹(group)입니다. 예를 들어 한 사용자가 sudo 명령어를 실행하기 위해서는, 동일한 이름(sudo)라는 이름의 그룹에 속해있어야 합니다.

컴퓨터에 어떤 그룹들이 있고, 해당 그룹마다 어떤 사용자들이 들어있는지 한번 확인해 봅시다. 유닉스 계열 운영체제에서는 설정 파일이나 장치 모두 파일로 접근 가능해야 한다는 철학이 있기 때문에, 그룹 설정도 텍스트 파일로 저장되어 있습니다.

❤️ cat: 하나 이상의 텍스트 파일을 순서대로 출력합니다.

$ cat /etc/group
root:x:0:
daemon:x:1:
bin:x:2:
sys:x:3:
adm:x:4:
tty:x:5:
disk:x:6:
lp:x:7:
mail:x:8:
news:x:9:
uucp:x:10:
man:x:12:
proxy:x:13:
kmem:x:15:
dialout:x:20:
fax:x:21:
[..생략..]


[cat 명령어는 고양이가 아니라 concatenate(이어붙이다)의 약자입니다.]
참고: 사용자들의 목록은 /etc/passwd에 기록되어 있는데, 원래 예전에는 해당 파일에서 사용자의 비밀번호까지 기록했기 때문입니다. 이제 대부분의 리눅스 기반 운영체제에서 비밀번호는 최고 관리자만 접근 가능한 /etc/shadow 파일에 암호화되어 저장됩니다.

접근 권한

그럼 누가 어떤 프로그램을 실행할 수 있는지는 어떻게 구분할까요? 다시 한 번, 프로그램도 파일이기 때문에, 프로그램 실행 권한은 파일 접근 권한과 동일한 방법으로 구분합니다.

프로그램과 디렉토리를 포함한 모든 "파일"에는 소유 사용자와 소유 그룹이 있습니다. 소유 사용자가 할 수 있는 일, 소유 그룹에 소속된 사용자들이 할 수 있는 일, 그리고 그 밖의 사용자들이 할 수 있는 일을 파일마다 설정할 수 있습니다. 이 설정값은 ls -lah 명령을 통해서도 확인할 수 있습니다.

$ ls -lah
total 48K
drwxr-xr-x 1 root root 4.0K Jun  7 08:34 .
drwxr-xr-x 1 root root 4.0K Jun  7 05:10 ..
drwxrwxrwx 2 root root    0 Jun  2 02:45 aiffel
-rw------- 1 root root  12K Jun  7 08:24 .bashrc.swp
drwxr-xr-x 1 root root 4.0K Apr 19 09:30 .cache
drwxrwsr-x 2 root root 4.0K Apr 19 09:30 .conda
drwx------ 3 root root 4.0K Jun  7 08:34 .config
drwxr-xr-x 2 root root 4.0K Jun  4 03:42 data
drwx------ 1 root root 4.0K Apr 19 09:23 .jupyter
drwxr-xr-x 3 root root 4.0K Jun  7 05:10 .local
-rw-r--r-- 1 root root  170 Apr 19 09:28 .wget-hsts

root 가 여러번 나오네요 3번 열은 소유 사용자이고, 4번째 열은 소유 그룹입니다. 위에 두 줄을 보면 현재 디렉토리(/aiffel, 여기서는 .)는 사용자로서 root과 그룹으로서 root이 소유하고 있으며, 그 위의 디렉토리(/, 여기서는 ..)는 사용자와 그룹으로서의 root가 소유하고 있음을 알 수 있습니다. 한번 이걸 변경해볼까요? 현재 디렉토리의 소유 사용자를 root로, 소유 그룹은 adm으로 변경했다가 복구해 보겠습니다.

👍️ chown: 대상 파일의 소유 사용자와 그룹을 변경합니다.

$ sudo chown root:adm .
$ ls -lah
total 48K
drwxr-xr-x 1 root adm  4.0K Jun  7 08:34 .
drwxr-xr-x 1 root root 4.0K Jun  7 05:10 ..
[..생략..]
root@wtetysocxvx7e6avqwhctccah-776475db6-h2swf:/# sudo chown root:root .
root@wtetysocxvx7e6avqwhctccah-776475db6-h2swf:/# ls -lah
total 92K
drwxr-xr-x   1 root root 4.0K Jun  7 05:10 .
drwxr-xr-x   1 root root 4.0K Jun  7 05:10 ..

참고로 위 명령어만으로는 디렉토리 내용물까지 소유자가 변경되지는 않습니다. 디렉토리 내의 모든 파일들에 대해 적용하려면 -R 옵션을 사용해야 합니다.

소유자 외에도, 위 ls -lah의 첫 열을 보면 drwxr-xr-x라고 무언가 적혀있는데, 이 부분이 바로 권한을 표기하는 부분입니다. 첫 글자인 d는 해당 파일이 디렉토리인지 또는 일반 파일인지 여부를 나타냅니다. 그 뒤를 잇는 글자들은 각각 3 글자씩 소유 사용자 , 소유 그룹 , 기타 사용자 에게 허용된 읽기(read, r) , 쓰기(write, w) , 실행하기(execute, x)

예를 들어 drwxr-xr-x는 해당 파일이 디렉토리이고(d), 소유자는 읽고(r) 쓰고(w) 실행(x)하는 모든 동작이 가능하지만, 소유 그룹 소속 사용자와 기타 사용자들은 읽고 실행하기만 가능하다는 것을 표시합니다.

권한은 숫자로도 표시할 수 있습니다. 기본적으로 세 가지 권한 rwx를 각각의 이진수 자리로 봅니다. 세 자리 이진수 숫자를 해석하면 사용자, 그룹, 기타 사용자에게 부여된 권한을 1자리 십진수 숫자로 나타낼 수 있습니다. 예를 들어 rwxr-xr-x를 이진수로 나타내면 111101101이고, 이는 구분 별로 다음과 같습니다.

  • 사용자: 이진수 111 = 십진수 7
  • 그룹: 이진수 101 = 십진수 5
  • 기타 사용자: 이진수 101 = 십진수 5
  • 종합: 755

참고로 실행하기(x)의 경우 프로그램이라면 실제 실행할 수 있다는 것을 나타내지만, 디렉토리의 경우 해당 폴더 안으로 cd로 이동할 수 있는지 여부를 나타냅니다.

chmod 명령어


chmod 명령어를 사용하면 권한을 변경할 수 있습니다. aiffel 폴더의 권한을 한번 변경해 봅시다. 모두에게 모든 권한을 끄기 위해서 숫자 표기로 000을 입력합니다. (000 = 000000000 = ---------) 아래와 같이 aiffel_test 디렉토리를 만들고 chmod 명령어를 활용하여 권한을 변경하여 보겠습니다. ^^

👍️ chmod: 대상 파일의 권한을 변경합니다.

$ mkdir aiffel_test
$ ls -lah
total 56K
drwxr-xr-x 1 root root 4.0K Jun  7 09:27 .
drwxr-xr-x 1 root root 4.0K Jun  7 05:10 ..
drwxrwxrwx 2 root root    0 Jun  2 02:45 aiffel
drwxr-xr-x 2 root root 4.0K Jun  7 09:27 aiffel_test
root@wtetysocxvx7e6avqwhctccah-776475db6-h2swf:~# chmod 000 aiffel_test/
root@wtetysocxvx7e6avqwhctccah-776475db6-h2swf:~# ls -l
d--------- 2 root root 4096 Jun  7 09:27 aiffel_test

3-5. 약간의 하드웨어

(1) 연산장치

지금까지 CPU, 메모리가 언급되었지만, 당사자인 하드웨어는 제대로 만나보지 못했습니다. 얼굴을 익히기 위해 한번 컴퓨터의 속을 까봅시다.

마더보드의 CPU Socket에는 CPU(Central Processing Unit, 중앙처리장치)가 올라갑니다. 실제로 CPU 칩의 크기는 얇지만, 보통 그 위에 냉각팬을 올리기 때문에 하드웨어를 직접 보면 커보입니다. 이 얇은 칩은 반도체인 실리콘 웨이퍼 위에 집적회로(Integrated Circuits, IC)를 포토리소그래피(photolithography) 공정을 통해 회로를 인쇄해 만듭니다.

칩이 만들어지는 과정이 더 궁금하신 분은 다음 영상을 참고하시면 좋습니다.

기계어
이렇게 제작된 CPU 칩이 처리할 수 있는 명령어는 기계어 라고도 하며, 우리가 사용하는 프로그래밍 언어와는 많이 다릅니다. 기계어로 프로그램을 직접 짜기에는 워낙 복잡하고 비효율적이기에 C, C++, Python 등 인간이 이해할 수 있는 프로그래밍 언어들이 만들어졌습니다. 이렇게 인간이 이해할 수 있는 언어로 짠 프로그램을 CPU에서 실행할 수 있는 기계어로 번역하고 최적화하는 과정이 바로 컴파일 입니다.

명령어 집합
회로 설계는 Intel, AMD 등 제조사마다 다르지만, 지원하는 연산 세트를 나타내는 명령어 집합(instruction set) 은 데스크탑용 CPU 간 상당 부분 호환됩니다. 다만 스마트폰 등 모바일 기기에 들어가는 CPU는 이야기가 다른데, 대부분 ARM 사의 RISC(Reduced Instruction Set Computer)라는 구조를 가지고, 지원하는 명령어는 더 적지만 전력을 더 적게 소비하는 방향으로 설계됩니다.

흥미롭게도 ARM 회사는 더 이상 직접 칩을 만들지 않고, 설계만 만들어 라이센스를 판매합니다. 이 설계를 원형으로 삼성전자(Exynos 등), 애플(A시리즈, M시리즈 등), 퀄컴(SnapDragon 등) 등 회사가 자신들의 목적에 맞게 변경하여 각자 칩을 생산합니다.

메모리와의 관계
CPU를 구분할 때에는 32bit와 64bit로 구분하기도 하는데, 이는 CPU가 한 번에 읽고 쓸 수 있는 데이터의 크기를 나타냅니다. 이 크기가 중요한 이유 중 하나는 사용 가능한 메모리 주소 의 범위에 영향을 주기 때문입니다.

이론적으로 32bit 컴퓨터에서는 2의 32승인 약 42억 개 메모리 주소공간만 사용할 수 있습니다. 1개 주소공간이 1 Byte라면 4GB 크기의 메모리 용량만 표기할 수 있기 때문에, 그 이상의 RAM을 사용할 수 없다는 큰 제한사항이 있었습니다.

CPU의 성능과 발전
CPU의 성능을 판단하는 주요 척도 중 하나는 초당 처리 속도의 기준인 클럭(clock)입니다. 하지만 요새 나오는 CPU를 보면 클럭이 4GHz에서 더 이상 발전하기보다는, 동시에 더 많은 스레드를 처리할 수 있도록 코어 수를 늘리는 방향으로 제조되고 있습니다. 이는 처리 속도를 높이기 위해 소비 전력을 높였다가는 물리적으로 냉각시키기가 너무 어려워지고, 그렇다고 전압을 낮춰서 낮은 전력으로 동작시키기에는 전류가 밖으로 누설되고, 그러면 전력과 전압을 모두 적절하게 유지하면서 집적도를 높이기에는 공정이 너무 미세해지면서(1~5 나노미터) 수율도 떨어지고, 현재의 소재들로는 양자 터널링 현상으로 인해 전자가 닫혀있는 게이트를 그냥 뛰어넘어버리게 되는 복잡한 물리적인/경제적인 이유 때문입니다.

다른 연산장치
이러한 한계로 인해 최근에는 CPU 외에도 특정 작업에 특화된 연산장치들이 떠오르고 있습니다.

그래픽 연산을 위한 GPU(Graphical Processing Unit) 이 그 중 하나입니다. CPU보다 이해할 수 있는 명령어는 훨씬 적지만, 코어 수를 훨씬 늘리는 방법으로 다차원 행렬 연산에 특화했습니다. 비유하자면 8 코어 CPU가 박사학위를 소지한 수학자 8명이라면, GPU는 (사칙연산밖에 못하지만 계산을 틀리지는 않는) 초등학생 3,000명을 모아놓은 것입니다. 복잡한 수식을 처리한다면 박사들이 유리하겠지만, 초등학교 수학 전집 100권을 빠르게 처리하기에는 초등학생들이 더 유리하겠지요.

딥러닝도 그래픽 연산과 유사하게 다차원 행렬을 계산하기 때문에 GPU를 많이 사용하지만, 최근에는 구글에서 딥러닝 전용으로 만든 TPU(Tensor Processing Unit) 처럼 전용 칩이 개발되고 있습니다.

이 외에 작업에 맞게 직접 설계하여 생산하는 ASIC(Application-Specific Integrated Circuit, 어플리케이션 특화 집적회로) 도 있으며, 그때그때 회로를 직접 프로그래밍해서 사용할 수 있는 FPGA(Field-Programmable Gate Array) 칩도 다양한 산업 분야에서 활용되고 있습니다.

(2) 저장장치

컴퓨터의 주 저장장치는 RAM(Random Access Memory) 입니다. RAM은 비싸서 용량을 쉽게 늘리기도 어렵고, 전원이 꺼지면 데이터가 사라집니다.

반면에 보조 저장장치인 HDD(Hard Disk Drive)SSD(Solid State Drive) 는 가격도 비교적 저렴하고, 전원이 꺼져도 데이터는 그대로 보존됩니다.

'저장'이라고 하면 하드디스크가 먼저 생각나지만, RAM이 주 저장장치인 이유는 연산장치인 CPU와의 속도 때문입니다. 아래 표를 보면 감을 잡을 수 있습니다. (참고로 CPU에도 연산을 돕기 위한 약간의 메모리(L1~L3 캐시)가 들어있는데, 이건 우리가 짜는 프로그램이 직접 관리할 수 없는 영역입니다.)

딥러닝과 저장장치

GPU를 쓰면 '연산'이 빨라져 딥러닝 모델이 무조건 빨라질 것 같지만, 사실 모델을 학습시키다 보면 속도에 병목 지점이 GPU/CPU 처리속도가 아닌 경우도 많습니다. (고화질 이미지로 모델을 학습시키는데 속도가 너무 느렸던 경우가 있으신가요?)

데이터를 읽어오는 데에 시간이 너무 많이 소요되고 있다면, 저장장치를 SSD로 변경하거나, 미리 여러 개의 스레드를 사용하여 RAM 메모리에 올려두는 방법으로 해결할 수 있습니다.

3-6. 클라우드와 가상화

클라우드 컴퓨팅


닷컴버블 초기, 미국의 전자상거래 업체 아마존(Amazon)은 주요 연휴마다 고객들이 몰려 서버가 다운되는 일을 겪었습니다. 그렇다고 연휴 기간의 최대 수요에 맞춰 평상시에도 많은 서버들을 유지하고 있자니 비용이 만만치 않다는 문제가 있었습니다. 이 문제가 자신들에게만 해당되지 않는다는 점을 깨달은 아마존은, 아마존 웹 서비스(Amazon Web Services) 라는 자회사를 설립하여, 수요에 따라 그때그때 서버를 빌렸다가 반납하는 서버 임대업을 시작합니다.

하지만 이 서버 임대업은 데이터센터에 위치한 물리적인 서버를 임대하는 것이 아니었습니다. 마치 런던에서는 치솟은 집값 때문에 방을 쪼개어 각각 임대하는 것처럼, 아마존은 한 대의 물리적인 서버를 여러 개의 가상 서버로 쪼개어 판매하기 시작했습니다. 클라우드 컴퓨팅이라는 말은 그 이전부터 존재했지만, 이때부터 본격적인 상업적 클라우드 컴퓨팅 시대가 시작됩니다.

가상화

가상화(virtualization) 는 이처럼 하나의 컴퓨터를 쪼개어 여러 대의 컴퓨터가 있는 것처럼 사용하게 하는 기술입니다. 가상화에서 실제 물리적인 서버를 호스트(host), 그 안에서 돌아가는 가상 서버를 게스트(guest) 라고 합니다.

가상화에는 여러 가지 종류가 있습니다. 가상머신(Virtual Machine) 가상화의 경우 게스트 자체에 운영체제가 돌아가지만, 컨테이너(Container) 가상화 의 경우, 마치 화장실과 주방을 공유하는 것처럼, 게스트들이 호스트의 운영체제 커널을 공유합니다. 물론 커널의 기능만 공유할 뿐, 프로세스나 자원 등은 서로 철저히 격리하여 서로 간섭할 수 없도록 하는 것이 핵심기술입니다.

도커(Docker) 는 이런 컨테이너 가상화를 손쉽게 제공하는 프로그램입니다. 한 곳에서 실행 환경(우분투 버전, 라이브러리, 필요한 프로그램들)을 컨테이너로 구성해놓은 다음에 그걸 그대로 클라우드로 가져가서 실행하거나, 굳이 클라우드가 아니어도 내 컴퓨터에서 여러 개의 독립된 작업 환경을 구분하는 데에 사용할 수 있습니다.

그렇다고 가상화가 무조건 클라우드 컴퓨팅과 함께하는 개념은 아닙니다. 내 컴퓨터에서 파이썬 버전을 여러 가지 사용하고 각각 패키지를 구분하여 관리할 수 있게 해주는 아나콘다(Anaconda)나 VirtualEnv는 클라우드 컴퓨팅과 크게 관계가 없지만, 가상화의 한 종류로 볼 수 있습니다.

3-7. 셸(shell) 심화

(1) 편리한 기능

  • 터미널 에뮬레이터에서 무언가를 복사하거나 붙여넣을 때에는 Ctrl+Shift+C, Ctrl+Shift+V를 사용해야 합니다.
  • 위아래 화살표를 통해 이전에 실행한 명령들을 다시 입력할 수 있습니다.
  • history 명령을 통해 기존에 실행한 명령들을 표시할 수 있습니다. 여기서 나오는 번호를 참고하여 !번호를 실행하면 해당 번호의 명령이 다시 실행됩니다.
  • Ctrl+A, Ctrl+E를 통해 명령어의 앞, 뒤로 커서를 이동할 수 있습니다.
  • clear 명령어 또는 Ctrl+L을 통해 기존에 터미널에 출력되었던 내용을 깨끗이 지울 수 있습니다.
  • 실수로 Ctrl+z를 눌러 프로세스를 중지시켰다면, fg를 통해 다시 재개시킬 수 있습니다.
  • 실수로 vi 편집기에 처음 들어갔다면, Ctrl+C 또는 Esc를 누른 뒤 :q!를 입력하고 엔터를 눌러 편집기를 종료할 수 있습니다.
  • sudo apt install curlcurl parrot.live를 통해 춤추는 앵무새를 볼 수 있습니다.( 클라우드에서는 작동이 안되니 로컬에서 테스트 해보세요 !)

(2) 셸 스크립트

명령어가 길거나, 명령어 여러 개를 이어서 실행해야 할 때, 명령어들을 파일로 묶어 실행할 수 있습니다. 한 줄에 한 명령어씩 적어주면 되고, #로 시작하는 주석을 넣을 수도 있습니다. 텍스트 편집기를 열어 test.sh라는 파일을 만들고, 다음 내용을 입력해 봅시다.

#!/bin/bash
echo "Hello"
# 주석
echo "Bye"

맨 위의 #!/bin/bash는 이 스크립트 파일을 실행할 때 어떤 프로그램을 사용해야 할지 알려줍니다. 또한 실제로 이 파일을 실행하기 위해 해당 파일에 chmod로 실행 권한을 추가해야 합니다.

$ chmod +x test.sh
$ ./test.sh
Hello
Bye

참고로 파이썬도 위의 규칙을 따라 스크립트 파일로 실행할 수 있습니다.

#!/usr/bin/python
print("Hello")

셸에도 파이썬처럼 조건문과 연산자들이 있습니다. ||를 써서 이전 명령이 false를 반환한 경우에만 다음 명령을 실행하거나, &&로 이전 명령이 true를 반환한 경우에만 다음 명령을 실행할 수 있습니다.

$ false || echo "false"
false
$ false && echo "false"
$ true && echo "true"
true
$ true || echo "true"

>를 통해 명령어의 결과를 파일에 저장하는 것도 가능합니다. >>를 쓰면 명령어의 결과가 기존 파일 뒤에 추가됩니다.

$ echo hello > test.txt
$ cat test.txt
hello
$ echo hello again >> test.txt
$ cat test.txt
hello
hello again

또는 |를 통해 앞의 명령어의 결과를 입력으로 받아 이어서 처리할 수 있습니다. 예를 들어 아래와 같은 내용의 텍스트 파일(fruits.txt)이 있다면,

Orange
Apple
Grape

다음 명령을 통해 순서를 정렬할 수 있습니다.

👍️ sort: 입력된 텍스트를 줄 단위로 정렬합니다.

$ cat fruits.txt
Orange
Apple
Grape
$ cat fruits.txt | sort
Apple
Grape
Orange

(3) 명령어 모음 및 추천자료

주의! 클라우드 환경
클라우드 환경은 도커를 이용해 생성됩니다.
도커 구성이 커질수록 클라우드 환경을 초기화 하는데 더 많은 시간이 필요합니다.
초기화하는 시간을 줄이기 위해 우분투 minimize버전을 사용하였습니다.
우분투 minimize버전은 반드시 필요하지 않은 구성 요소를 제외한 것인데요.
이 때문에 클라우드 환경에서는 몇 명령어가 제대로 동작하지 않을 수 있습니다.

명령어 모음

필수(❤️) 및 권장(👍) 명령어들은 한번씩 실행하거나, 사용법을 검색해 보는 것을 추천합니다.

  • 셸 환경
    • 👍history: 셸 명령어 이력을 출력합니다.
    • 👍man: 프로그램의 매뉴얼 페이지를 출력합니다.
    • 👌which: 명령어의 전체 경로를 출력합니다.
    • 👌export: 셸 변수나 함수를 현재 환경으로 내보냅니다.
    • 👌env: 명령어가 제공된다면 해당 명령어를 새로운 환경에서 실행합니다. 명령어가 제공되지 않은 경우 현재 환경의 정보를 출력합니다.
  • 텍스트 처리
    • ❤️echo: 뒤이어 입력한 내용을 출력합니다.
    • ❤️cat: 하나 이상의 텍스트 파일을 순서대로 출력합니다.
    • 👍sort: 입력된 텍스트를 줄 단위로 정렬합니다.
    • 👍less: 텍스트 파일의 내용을 자유롭게 조회하고 검색합니다.
    • 👍head: 텍스트 파일의 앞 몇 줄만 출력합니다.
    • 👍tail: 텍스트 파일의 마지막 몇 줄만 출력합니다.
    • 👍cut: 텍스트를 구분자(delimiter)에 따라 나눕니다.
    • 👍uniq: 텍스트 중 중복 값들을 제거합니다.
    • 👍grep: 정규식을 활용해 텍스트를 검색합니다.
    • 👍wc: 텍스트를 단어, 줄, 문자 등 단위로 셉니다.
    • 👌comm: 텍스트 파일을 비교합니다.
    • 👌zcat: 압축된 텍스트 파일을 출력합니다.
    • 👌sed: 정규식을 활용해 텍스트를 변형합니다.
    • 👌awk: 텍스트를 스캔하고 변형합니다.
  • 파일 제어 및 이동
    • ❤️ls: 현재 디렉토리 내의 파일 및 폴더들을 출력합니다.
    • ❤️cd: Change Directory의 약자로, 뒤에 따라오는 폴더로 내가 있는 셸의 현재 위치를 이동시킵니다.
    • ❤️cp: 파일을 복사합니다.
    • ❤️mv: 파일을 이동합니다.
    • ❤️rm: 파일을 삭제합니다. 폴더를 삭제하기 위해서는 -r (recursive) 옵션을, 빈 폴더가 아니더라도 내부까지 삭제하려면 -f (force) 옵션을 함께 사용해야 합니다.
    • 👍chown: 대상 파일의 소유 사용자와 그룹을 변경합니다.
    • 👍chmod: 대상 파일의 권한을 변경합니다.
    • 👍find: 파일을 찾습니다.
    • 👍pwd: Present Working Directory의 약자입니다. 현재 내가 >위치한 디렉토리 위치를 출력합니다.
    • 👌ln: 파일에 대한 링크를 생성합니다.
    • 👌touch: 파일 접근 및 수정 시간을 변경합니다. 빈 파일을 만드는데도 사용할 수 있습니다.
    • 👌tar: 파일 및 폴더를 하나의 아카이브 파일로 통합하고 압축합니다.
    • 👌mount: 새로운 저장장치를 파일시스템으로서 추가합니다.
    • 👌rename: 여러 파일들의 이름을 규칙에 따라 한번에 변경합니다.
    • 👌df: 파일시스템의 남은 용량을 표시합니다.
  • 시스템 및 프로세스 제어
    • ❤️sudo: 이어지는 명령을 최고 관리자 권한으로 실행합니다.
    • ❤️apt-get: APT 패키지 관리자를 통해 공인 저장소에서 패 >키지를 가져다 설치하거나 제거합니다.
    • 👍ps: 현재 프로세스 목록을 출력합니다.
    • 👍kill: PID에 해당하는 프로세스에 시그널을 보냅니다.
    • 👌fg: 배경에서 실행되는 작업을 전경(foreground)으로 가져옵니다.
    • 👌bg: 작업을 배경(backgound)으로 보냅니다.
    • 👌jobs: 전경 및 배경 작업의 목록을 표시합니다.
      기타
    • ❤️ssh: 원격으로 셸에 접속합니다.
    • 👍tmux: 여러 개의 셸 세션을 관리하고, 터미널 접속이 끊어지더라도 셸 세션을 유지합니다.
    • 👍watch: 이어지는 명령을 주기적으로 실행하여 표시합니다.
    • 👍curl: 주어진 URL과 통신합니다.
    • 👍wget: 네트워크를 통해 파일을 다운로드합니다.
    • 👍scp: SSH를 통해 원격으로 파일을 전송합니다.
    • 👌ssh-keygen: SSH 공개키 비밀키 쌍을 생성합니다.
    • 👌ssh-copy: SSH 공개키를 해당 서버에 등록합니다.
    • 👌rsync: 원격으로 파일을 동기화합니다.
    • 👌xarg: 명령어를 구성하여 실행합니다. 이전 명령에서 인자를 넘겨받아 실행하거나, 다중 프로세스를 사용하여 명령을 병렬로 실행하는 등의 작업이 가능합니다.
    • 👌cron: 주기적으로 실행될 명령을 등록합니다.
    • 👌htop: 프로세스 목록 및 자원 사용량을 시각적으로 표시합니다.
  • 추천 자료
    만화로 배우는 리눅스 시스템 관리 1 : 명령어 & 셸 스크립트 입문

'리눅스/Linux 일반' 카테고리의 글 목록

(4) 연습문제

Q1. 클라우드 환경의 현재 위치를 확인하고, 현재 위치에 존재하는 파일과 폴더들을 확인해봅니다.

$ pwd 
$ ls

Q2. data폴더로 이동하고 titanic.csv에서 남성과 여성이 몇 명인지 세어봅시다. 우선 tail 을 통해 첫 줄을 제외한 나머지 줄을 출력하고, cut으로 성별이 들어있는 열만 추출한 다음, ④로 뭔가 쓱싹 한 다음에 uniq로 각각 세어봅시다.

클라우드 환경에서는 이미 ~/data 경로에 titanic.csv 파일이 다운로드 되어있습니다.

titanic.csv 데이터 정보 보기

$ cd ~/data
$ ls -l
$ tail -n ① titanic.csv | cut -d② -f③ | ④ | uniq ⑤ 
314 female
577 male

Q3. titanic.csv에서 성이 Brown인 사람이 몇 명인지 세어봅시다. 성이 아닌 나머지 이름에 Brown이 들어가는 경우도 있으니 조심해야 합니다.

$ cat titanic.csv | grep '①' | wc ②

수고하셨습니다!

profile
게임광 AI 그루~~

0개의 댓글