shell
은 command를 실행시키는 하나의 program으로 window의 terminal
과 비슷하다. shell이 실행하는 command는 일종의 program이 될 수 있으며, shell에서 기본적으로 제공하는 built-in feature들도 있다.
대부분의 시스템의 중요한 부분들은 사실 일련의 shell 명령어를 실행시키는 shell script
라는 text file들이다. 실제로 우리가 사용하고 동작시키는 program의 대부분이 shell script로 동작하거나, 많은 부분들이 사용되고 있는 경우들이 많다.
현재 대부분의 linux 배포판들이 Borune-again shell
인 bash
를 사용하고 있다. bash
는 리눅스 배포판에서 /bin/sh
에 링크되어있어, 이를 통해 쉽게 shell programming을 할 수 있다.
shell을 실행시키는 GUI를 흔히 terminal
이라고도 한다. terminal
을 실행시킨다음에 다음의 명령어를 실행시켜보도록 하자.
참고로 $
는 shell의 prompt이므로, 맨왼쪽에 기본적으로 있을 것이다.
$ cat /etc/passwd
shell script의 명령어들은 대부분 program
, arguments
구조이다. 위에서는 cat
이라는 program을 실행하되 /etc/passwd
를 arguments로 받겠다는 것이다. cat
은 입력받은 file의 데이터를 읽어 화면에 보여주는 기능을 하고, 그 file이 바로 /etc/passwd
인 것이다.
이 argument
가 무엇이냐에 따라 program
의 동작이 달라지는데, argument
말고도 option
과 environment variables
들도 있다. 이에 대해서는 더 command들을 사용해보면서 배워보도록 하자.
cat
program의 사용 방법은 다음과 같다.
$ cat file1 file2 ...
여러 개의 file들을 받아서 한 번에 shell로 뽑아주는 역할을 하는 것이다.
unix process들은 I/O stream을 사용하여 data를 읽고 쓴다. process는 input stream들에서부터 data읽고, output stream으로 data를 쓰는데, 여기서 input stream은 file, device, terminal window, 혹은 또 다른 process의 output stream일 수 있다.
cat
을 아무런 파라미터없이 실행시켜보면 계속 실행된 채로 shell에 있을 것이다. CTRL-D
를 누르면 강제로 종료시킬 수 있는데, 왜 cat
을 입력없이 실행하면, 계속 shell에 실행된 채로 존재하냐면, 이는 I/O stream과 관련이 깊다. cat
을 그냥 실행하면 cat
은 file이 아니라 linux 커널에 의해 제공받은 standard input stream을 읽는다. 따라서, 계속 입력이 들어올 때까지 기다리게 되는 것이다. 여기서의 input stream은 바로 terminal이므로 terminal input stream이 cat
에 할당되는 것이다.
linux의 모든 process들은 kernel에 의해 I/O stream을 모두 할당받는다. 이는 cat
역시도 마찬가지인데, cat
command는 항상 standard output stream에 결과를 출력한다. cat
을 terminal에서 실행하게되면 standard output stream이 terminal
에 연결되는 것이다.
이러한 standard input, output stream을 짧게 stdin
, stdout
이라고 한다. 여기에 더불어 error를 출력하는 standard error도 존재한다. 이러한 standard stream의 가장 중요한 점은 바로 쉽게 어디서 data를 읽고, 어디에 data를 쓸지 제어할 수 있다는 것이다. 가령, cat
의 stdout을 terminal로 할지 특정 file로 할지 설정할 수 있다.
ls
는 directory의 content들을 나열해준다. 즉 입력 parameter로 받은 directory 안의 file들과 directory들을 보여준다.
$ ls -l
total 3616
-rw-r--r-- 1 juser users 3804 May 28 10:40 abusive.c
-rw-r--r-- 1 juser users 4165 Aug 13 10:01 battery.zip
-rw-r--r-- 1 juser users 131219 Aug 13 10:33 beav_1.40-13.tar.gz
-rw-r--r-- 1 juser users 6255 May 20 14:34 country.c
drwxr-xr-x 2 juser users 4096 Jul 17 20:00 cs335
-rwxr-xr-x 1 juser users 7108 Jun 16 13:05 dhry
-rw-r--r-- 1 juser users 11309 Aug 13 10:26 dhry.c
-rw-r--r-- 1 juser users 56 Jul 9 15:30 doit
drwxr-xr-x 6 juser users 4096 Feb 20 13:51 dw
-l
옵션을 추가하면 자세한 항목들을 보여준다. -F
옵션을 추가하면 file에 대한 type정보까지 나열해준다.
두번째 column은 해당 file에 대한 hard link라는 것인데, 이에 대해서는 추후에 배워보도록 하자.
cp
는 file들을 복사한다. file1
을 file2
로 복사하고 싶다면 다음과 같이 쓸 수 있다.
$ cp file1 file2
cp
의 destination을 file2
와 같은 file이름이 아니라, directory를 써도 된다. 그렇게하면 원래 file이름을 기준으로 destination directory에 file을 새로 복사해준다.
$ cp file dir
여러 file들을 direcotry에 복사하고 싶다면 다음과 같이 나열하면 된다.
$ cp file1 file2 file3 dir
mv
(move) 명령어는 cp
와 비슷한데, file의 위치를 이동시키는 기능을 한다. 이 기능을 이용하여 이름만 바꾸도록 할 수도 있다.
아래는 file1
을 현재 directory로 이동하되 file2
로 이름을 바꾸라는 말이다.
$ mv file1 file2
만약 다른 directory로 현재 이름을 가지고 이동시키고 싶다면 다음과 같이 쓰면 된다.
$ mv file1 /path/directory/file2
touch
는 file을 하나 새로 만들어주는데, 만약 target file이 이미 존재한다면 touch
는 기존 file의 내용을 바꾸진 않는다. 다만 file의 수정 timestamp는 변동된다. 가령, 빈 file을 만들기 위해서는 다음과 같이 쓸 수 있다.
$ touch file
만들어진 해당 file에 대해서 ls -l
을 쓰면 다음과 같은 결과를 볼 수 있을 것이다.
$ ls -l file
-rw-r--r-- 1 juser users 0 May 21 18:32 file
변동에 대한 timestamp를 보고 싶다면 tocuh file
명령어를 한 번더 입력하고, 1분만 기다려서 ls -l
을 입력해보면 된다.
rm
은 file을 없애는 명령어인데, 굉장히 조심해야한다. file을 지운다음 백업을 하지 않는 이상 되돌릴 방법은 없다.
$ rm file
echo
명령어는 입력으로 받은 argument를 읽어 stdout에 출력해준다.
$ echo Hello again.
Hello again.
echo
는 매우 중요한 명령어이므로 이후에 쭉 나올 것이다.
path를 표현하는데 있어서 여러가지 방벙이 있다.
./
: 현재 directory를 나타낸다. 가령 현재 directory에서 file1
을 선택하고 싶을 때는, ./file1
을 쓰면 된다.../
: 이전 directroy를 나타낸다. 현재 directory에서 이전 direcotry가 file2
를 가지고 있었다면, ../file2
로 쓰면 된다./
: absolute path인 절대 경로를 말한다. root
path부터 시작하여 경로를 탐색한다. 가령, root path의 usr
directory에 접근하고 싶다면 /usr
로 쓰면 된다.각 process는 독립적으로 현재 동작중인 direcotry를 가지고 있다. cd
명령어는 shell의 현재 동작중인 directory를 변경하는 명령어인 것이다.
가령 dir
directroy로 이동하고 싶다면 다음과 같이 쓰면 된다.
$ cd ./dir
만약 dir
과 같은 입력 parameter를 생략하면 home directory로 간다.
mkdir
명령어는 새로운 directory를 만드는 명령어로 dir
과 같은 directory를 만들고 싶다면 다음과 같이 쓸 수 있다.
$ mkdir dir
rmdir
명령어는 directory를 삭제하는 명령어이다. 가령 dir
과 같은 directroy를 삭제한다고 할 대 다음과 같이 쓸 수 있다.
$ rmdir dir
만약, 삭제하려는 directory가 비어있지않다면 삭제되지 않음에 유념하자. 그러나 하나하나 directory에 있는 file들을 삭제하는 것은 매우 귀찮은 일이다. 이를 해결할수 있는 명령어가 바로 rm -r
이다. -r
은 recursive하게 반복적으로 directory안에 있는 file들을 삭제하라는 말이다. 이는 매우 조심해야하는 명령어인데, 한 번 삭제시키면 다시 복구가 불가능하기 때문이다.
shell은 간단한 pattern을 이용하여 특정 file들과 directory들을 매칭시킬 수 있다. 이 process가 바로 globbing
이다. 이 동작은 wildcard와 매우 유사하다. glob 문자 중 가장 많이 사용되는 것이 *
이다. 이는 shell에게 임의의 어떤 문자열이든 매칭된다는 것을 나타내는 glob 문자이다. 가령, 다음의 명령어는 현재 Directory의 모든 file list들을 보여준다.
$ echo *
shell은 glob을 포함한 인수를 파일 이름과 일치시키고 해당 인수를 파일 이름으로 대체한 다음 수정된 명령을 실행한다. shell이 단순화된 표현식에 대해 일치하는 모든 파일 이름을 치환하기 때문기 때문에, 이를 expansion(확장)이라고 한다. *
은 파일 이름을 expansion하는데 사용하는 몇 가지 방법들을 제공한다.
at*
: at
으로 시작하는 모든 파일이름으로 확장*at
: at
으로 끝나는 모든 파일이름으로 확장*at*
: `at이 포함된 모든 파일 이름으로 확장또 다른 shell glob 문자는 ?
이다. ?
은 *
처럼 임의의 문자가 어느 것이든 맞으면 되는데, *
와는 달리, 단 하나의 문자만을 허용한다. 가령 b?at
이라면 boat
와 brat
이 있다.
그런데, 만약 glob 문자를 적용시키지 않고 *
나 ?
자체를 출력하고 싶을 때는 어떻게 할까?? 이때는 ''
으로 감싸주면 된다. 가령 echo '*'
로 감싸주면 globbing이 실행되지 않고 *
문자가 출력된다.
shell의 globbing이 중요한 이유는 명령어를 실행하기 이전에 expansion(확장)을 통해서 명령어를 바꾸어 실행한다는 것이다. 즉, 명령어 실행 전에 명령어 자체를 globbing을 통해 바꾼다는 것이다. 만약, expansion동작이 없다면 *
은 아무런 동작을 하지 않을 것이다. 따라서, shell에서의 동작을 명령하는 것은 명령어이지 shell이 아니다.
grep
은 file또는 input stream으로부터 표현식에 매칭되는 line을 출력해준다. 가령, /etc/passwd
file에서 root
text에 매칭되는 line을 뽑고 싶을 때는 다음과 같이 쓸 수 있다.
$ grep root /etc/passwd
grep
은 정말 많이 사용되는 기능이다. 가령, /etc/
directory에서 이름에 root
가 붙은 파일을 가져오고 싶다면 다음과 같이 쓸 수 있다.
$ grep root /etc/*
grep
에서 많이 사용되는 option은 두 가지 정도만 알아보도록 하자.
-i
: cast-insensitive로 대소문자를 구별하여 매칭시킬 때 사용한다.-v
: 검색 결과를 뒤집는(invert)한다는 의미인데, 매칭되는 line의 결과 이외의 결과들을 출력해준다. -E
옵션은 확장된(extended) 정규표현식을 사용한다는 이야기이다. 즉, default는 basic 정규표현식인데, -E
를 사용하면 확장된 정규표현식을 사용한다. grep -E
와 egrep
은 유의어라고 보면 된다.
grep
은 basic 정규 표현식을 기본으로 지원하여 매칭에 사용한다는 것을 알아두도록 하자.
less
를 사용하면 큰 file들에 대한 문자들을 scroll을 하여 손쉽게 볼 수 있다. 가령 /usr/share/dict/words
를 cat
으로보면 너무 많아서 천천히 보기 힘든데, less
를 사용하면 scroll이 다운되면서 천천히 볼 수 있다.
spacebar
를 누르면 쭉쭉 읽은 file의 내용들을 scroll 다운해주고, q
를 누르면 종료한다.
/
을 사용하여 매칭되는 문자들을 검색할 수도 있다. /word
로 검색하면 앞부터 word
를 가진 문자열을 검색하여 매칭되는 결과를 찾는다. 반대로 뒤부터 검색해서 매칭되는 검색을 하기 위해서는 ?word
로 쓰면 된다.
less
는 grep
과 같이 많이 사용되는데, |
을 사용하면 grep
의 검색 결과를 less
에 보낼 수 있다.
다음의 명령어는 /usr/share/dict/words
파일에 있는 text중에 ie
를 가진 text결과를 less
에 보내어 실행시키는 것이다.
$ grep ie /usr/share/dict/words | less
pwd
는 'print working directory'라는 program으로 현재 shell prompt가 가리키고 있는 directory의 path를 보여준다.
$ pwd
pwd
를 통해서 현재 working directory를 파악하고, 다른 os나, shell, 환경에서도 같은 동작을 할 수 있도록 자동화 스크립트들을 만들 수 있는 것이다.
두 text file의 차이를 확인하고 싶다면 diff
를 사용하면 된다.
$ diff file1 file2
기본적으로 diff
는 사람이 읽기 편한 output을 도출하는데, -u
옵션을 사용하면 기계입장에서 읽기 쉬운 결과로 반환해준다. git을 사용해보았다면 git diff를 사용했을 때의 msg가 바로 그렇다.
diff -u ./result.csv ./result2.csv
--- ./result.csv 2024-06-22 15:58:46
+++ ./result2.csv 2024-06-22 15:59:10
@@ -5,8 +5,8 @@
2023-07-01,hiring_site,2,-50.0
2023-08-01,direct_to_company,2,-33.34
2023-08-01,hiring_site,4,100.0
-2023-08-01,linkein,0,0.0
-2023-08-01,recommand_by_company,0,0.0
+20238-01,linkein,0,0.0
+2023-001,recommand_by_company,0,0.0
2023-09-01,recommand_by_company,2,0.0
2023-09-01,direct_to_company,2,0.0
2023-09-01,hiring_site,9,125.0
file의 형식을 알고싶다면, file
을 사용하면 된다.
$ file file
가령 CSV파일이라면 다음과 같이 나온다.
file ./result.csv
./result.csv: CSV text
만약 특정 file이 directory tree안에 있는 것은 알지만, 정확히 어디에 있는 지는 모를 때, find
를 사용하여 정확한 위치를 알 수 있다.
$ find dir -name file -print
locate
명령어 역시도 file을 찾아주지만, find
와 달리 index기반이라 index를 한 번 업데이트해놓고 참조하는 방식이다. 따라서, 속도는 더 빠르지만 file의 위치가 달라지면 그 결과가 달라질 수 있다.
head
와 tail
은 file 또는 stream data의 일부를 빠르게 볼 수 있도록 해준다. 가령, head /etc/passwd
를 사용하면 /etc/passwd
파일의 맨 앞 10줄을 보여준다. tail /etc/passwd
는 마지막 10줄을 보여준다.
10줄이 아니라 n줄만큼 보고 싶다면 -n
을 사용하면 된다. 가령 5줄만 보고 싶다면 heat -5 /etc/passwd
라고 쓰면 된다. tail의 경우는 반대로 +n
으로 쓰면 된다. 아래의 5줄을 보고 싶다면 tail +5
으로 써주면 된다.
sort
명령어는 빠르게 text file의 각 줄을 알파벳 순서로 정렬해준다. 만약 file의 줄이 숫자로 시작하여 숫자로 정렬하고 싶다면 -n
option을 사용하라 -r
옵션은 정렬을 반대로한다.
shell은 일시적인 변수들을 저장할 수 있는데, 이 변수를 shell variable
이라고 한다. 이 shell variable
을 통해서 shell script가 동작하는 방식들을 제어할 수 있는 것이다.
다음과 같이 shell variable을 할당할 수 있다.
$ STUFF=blah
STUFF
변수에 'blah'
라는 문자열을 넣은 것이다. 이 변수에 접근하기 위해서는 $
을 사용하면 된다. $STUFF
라고 쓰면 'blah'
가 나오는 것이다. echo $STUFF
라고 써보면 'blah'
가 나오는 것을 볼 수 있을 것이다.
shell variable을 할당할 때
=
사이에는 공백을 넣지말도록 하자.
environment variable은 shell variable과 비슷하지만 shell에만 국한되지 않는다. 이는 재밌는 특성을 가지는데, shell variable은 shell variable이 선언되어 할당된 곳에서만 사용이 가능한 반면에 environment variable은 부모의 environment variable까지 상속받기 때문에 child process가지 영향을 주는 것이다.
environment variable을 할당하는 방법은 export
를 사용하면 된다. 가령 STUFF
shell variable을 environment variable로 할당하기 위해서는 다음과 같이 쓰면 된다.
$ STUFF=blah
$ export STUFF
PATH
는 special한 환경 변수로서 command path(= path) list를 나타낸다. shell은 특정 명령어를 실행할 때 command path로 부터 해당 명령어가 있는 지 찾는다. 가령, ls
라는 명령어가 어디에 있는 지 PATH
환경 변수를 통해 찾아내고 실행하는 것이다.
만약, 동일한 이름의 program이 command path에 여러 개 있다면, 가장 처음에 나온 program만을 실행한다.
command path는 콜론 :
단위로 각 directory path를 구분하기 때문에 아래와 같이 :
로 각 path들이 분리된 것을 볼 수 있다. 즉, /usr/local/bin
과 /usr/bin
과 /bin
이 있는 것이다.
$ echo $PATH
/usr/local/bin:/usr/bin:/bin
만약, 특정 directory를 command path에 추가하고 싶다면 다음과 같이 PATH
를 업데이트해야한다.
$ PATH=dir:$PATH
$ PATH=$PATH:dir
command path가 망가지지 않게 조심하는 것이 좋지만, 이 값은 환경변수이기 때문에 위와 같이 단순 선언으로 바꾸면 결국 shell의 하위 process까지만 영향을 미치므로, 기존 shell을 끄고 새로운 shell을 키면 된다.
Linux에서 자주 사용되는 special character들이 있다. 이들은 특별한 기능을 하기 때문에 꼭 알아두도록 하자.
Character | Name(s) | Uses |
---|---|---|
* | star, asterisk | Regular expression, glob character |
. | dot | Current directory, file/hostname delimiter |
! | bang | Negation, command history |
| | pipe | Command pipes |
/ | (forward) | slash Directory delimiter, search command |
\ | backslash | Literals, macros (never directories) |
$ | dollar | Variables, end of line |
' | tick, (single) quote | Literal strings |
` | backtick, backquote | Command substitution |
" | double quote | Semi-literal strings |
^ | caret | Negation, beginning of line |
~ | tilde, squiggle | Negation, directory shortcut |
# | hash, sharp, pound | Comments, preprocessor, substitutions |
[ ] | (square) brackets | Ranges |
{ } | braces, (curly) brackets | Statement blocks, ranges |
_ | underscore, under | Cheap substitute for a space used when spaces aren’t wanted or allowed, or when autocomplete algorithms get confused |
stdin, stdout을 다른 곳으로 redirect시킬 수 있는 기능이 있는데, 먼저 stdout을 terminal이 아니라 특정 file로 보내는 기능에 대해서 알아보도록 하자.
$ command > file
특정 명령어를 실행시킨다음, 그 결과인 stdout을 file
에 보내어 저장하고 싶다면 redirect명령어인 >
을 사용하면 된다.
shell은 file
을 만들어 stdout 내용을 file
안에 저장한다. 그런데, 만약 file
이 이미 있었다면 file
을 지운다음, 새로 만들어 내용을 채운다. 이를 clobber
라고 하는데, set -C
를 입력하면 이러한 동작을 막을 수 있다.
만약, 전체 내용을 지우고 다시쓰는 것이 아니라, 덧붙이고 싶다면 >>
을 쓰면 된다. 그러면 stdout
을 file
마지막 부분에 추가할 것이다.
$ command >> file
명령어의 stdout을 다른 명령어의 stdin에 연결하는 파이프라인 기능은 pipe 문자인 |
을 사용하면 된다. 다음의 두 명령어를 실행해보도록 하자.
$ head /proc/cpuinfo
$ head /proc/cpuinfo | tr a-z A-Z
head
의 결과인 stdout이 tr
의 입력인 stdin
으로 들어가는 것이다.
분명 특정 명령어의 stdout을 다른 곳으로 redirecting했는데, terminal에 text가 찍힌 것을 볼 수 있을 것이다. 이를 stderr
(standard erro)라고 한다. 이는 추가적인 output stream으로 진단과 디버깅을 위한 것이다. 다음의 예제를 보도록 하자.
$ ls /fffffffff > f
실행 후에 f
를 보면 아무런 문자도 찍혀있지 않을 것이다. 그러나 terminal에는 다음의 error가 나왔을 것이다.
ls: cannot access /fffffffff: No such file or directory
이러한 standard error를 다른 곳으로 redirect할 수 있는데, >
가 아니라 2>
를 사용하면 된다.
$ ls /fffffffff > f 2> e
2
의 의미는 stream id로 기본적으로 stream id는 1이고, 1은 stdout이다. 따라서, 2라고 써주면 stream id 2인 stderr
를 말하는 것이다. 따라서, e
파일에 stderr text가 쓰여질 것이다.
만약, stderr를 stdout으로 보내고 싶다면 2>&1
d으로 써주면 된다.
file의 결과를 command의 stdin에 redirect시키고 싶다면 <
을 써주면 된다.
$ head < /proc/cpuinfo
그러나 사실 대부분의 command들이 stdin을 입력 파라미터로 받고 있기 때문에 굳이 필요하진 않다.
system의 각 process는 process id(PID)를 가지는데, ps
입력하여 process list에서 PID를 확인하여 보자.
$ ps
PID TTY STAT TIME COMMAND
520 p0 S 0:00 -bash
545 ? S 3:59 /usr/X11R6/bin/ctwm -W
548 ? S 0:10 xclock -geometry -0-0
2159 pd SW 0:00 /usr/bin/vi lib/addresses
31956 p3 R 0:00 ps
PID
: process idTTY
: 추후에 설명하겠지만, process가 동작중인 terminal device를 말한다.STAT
: process status로 process가 무엇을 하고 있는 지 알려준다. S
라면 sleep이고, R
은 running이다.TIME
: CPU time를 할당받은 시간으로 processor를 통해 명령어 집합들을 실행한 총 시간이 된다.COMMAND
: program을 실행시키기 위해서 사용된 command이다. 한가지 명심할 것은 process가 실행되면서 이 값을 변경할 수도 있으며, glob expansion을 사용하여 원래의 명령어와 다르게 실행될 수 있다.ps
명령어는 현재 process를 보여주는 명령어인데, 옵션이 다양하다.
ps x
: 동작 중인 process만 보여준다.ps ax
: system에 속한 모든 process들을 보여준다.ps u
: process에 대한 자세한 정보를 포함하여 보여준다.ps w
: 전체 명령어 이름들을 모두 보여준다.ps aux
, ps auxw
와 같이 다양하게 옵션들을 섞어서 사용할 수 있다.
재밌는 trick이 하나있는데, shell
에서 $$
을 사용하면 현재 실행 중인 shell script의 PID
를 반환한다. 따라서, 현재 shell에 대한 process 정보를 얻고 싶다면 ps u $$
라고 쓰면 된다.
process를 종료시키기 위해서는 kernel로부터 process에게 signal
을 보내야 한다. 이 정료 signal을 보낼 수 있는 방법 중 하나가 kill
이다.
$ kill pid
signal은 여러가지 종류들이 있는데, default는 TERM
또는 terminate이다. 다른 옵션들을 추가하여 다른 signal들을 보낼 수도 있는데, 가량, process를 종료시키지말고 잠시만 동작을 멈추도록 STOP
signal을 보낼 수도 있다.
$ kill -STOP pid
stop signal을 받은 process는 동작은 멈추지만 계속해서 메모리에 남아있게 되어 다시 동작시킬 수 있다. CONT
옵션을 추가하여 요청을 보내보면 된다.
$ kill -CONT pid
사실 우리가 process를 실행시켜놓고 종료할 때 ctrl+c
를 누르는데, 이 명령어 자체가 kill
을 사용하여 process에게 interrupt
signal을 보내는 것과 같다.
kernel은 process에게 signal을 보내고 process가 자신의 업무를 마무리할 시간을 충분히 준다. 즉, process가 여러 데이터들을 정리하고, graceful하게 종료할 로직들을 실행할 수 있도록 해주는 것이다.
그러나, 몇몇 process들은 이러한 signal들이 들어오면 process를 종료하는게 아니라, 쳐내어버리거나 따로 처리하여 적절한 조치를 취한다. 문제는 사용자 입장에서 종료되지 않은 process이기 때문에, 반드시 종료해야할 경우 문제가 발생한다.
이 때 사용하는 signal이 바로 KILL
signal이다. kill -KILL
signal을 발생시키면 kernel은 process가 graceful하게 동작할 시간도 주지 않고 memory에서 없애버린다. 즉, 강제로 process를 메모리에서 삭제하는 것이다.
signal은 숫자로 맵핑되어있기 때문에 종종 숫자로 쓰는 경우들을 본적이 있을 것이다. kill -9
는 kill -KILL
과 같다. 이에 대한 mapping table을 보고 싶다면 kill -l
을 확인해보도록 하자.
shell은 'job control'를 지원하는데, 이는 STOP
signal과 유사한 TSTP(temporary stop)
와 CONT
signal을 program들에게 보내는 방식으로 여러 명령어와 keystroke를 통해 실행할 수 있다. 이는 개발자가 사용중인 program들 사이에 지연, 변경을 가능하게 해준다. 가령 CTRL-Z
를 누르면 TSTP
signal을 보낸다음 fg(foreground)
또는 bg(background)
를 입력하여 process를 다시 시작시킬 수 있다.
그러나, 대부분 CTRL-Z
를 눌러 process를 잠시 멈추도록 한 뒤에 까먹고 잊어버린다. CTRL-Z
는 CTRL-C
와 다른데, process가 suspend한 상황에 있게 되는 것이지, 메모리에서 아예 사라지는 것은 아니다. 만약, CTRL-Z
를 눌러 웹서버를 멈추게 한다해도 port
는 웹서버가 가지고 있게 되는 것 또한 메모리에서 없어지지 않았기 때문이다.
만약, suspend시킨 process가 무엇이 있는 지 보고 싶다면 jobs
명령어를 입력해보도록 하자.
만약 shell에서 특정 process를 구동시킴과 동시에 shell을 그대로 쓰고시다면, background process를 사용하면 된다. 이는 shell process에서 실행한 명령어로 만들어진 process를 떼어내어 현재의 shell과는 인터렉티브하지 않은 동작을 시켜주는 것이다.
background process를 만드는 방법은 생각보다 어렵지 않은데, 명령어 prompt 맨 마지막에 &
를 사용해주면 된다.
$ gunzip file.gz &
다음은 gunzip
command를 실행시킨다음, gunzip
process를 background로 구동시켜주는 code이다. 해당 명령어를 실행하면 바로 shell prompt를 얻게되고, background에서 gunzip
process가 동작한다. background 동작이 끝나면 현재의 shell에 그 결과를 알려준다는 사실을 알도록 하자.
background process의 가장 큰 문제는, 만약 stdin을 받기를 원하는 process를 background process로 구동시킨다면 process는 입력받은 값이 없기 때문에 계속해서 대기에 걸린다. 이를 해소시킬 수 있는 방법은 foreground process로 바꾸러 주도록 fg
명령어를 실행시키거나 종료시키는 방법 밖에 없다.
또한, stdout과 stderr를 반환 할 때도 문제인데, 이 결과 output이 현재 동작중인 shell에 뜬금없이 출력된다는 것이다. 이는 로깅이나, 디버깅, 동작 확인을 더욱 어렵게 하는 문제가 있다.
따라서, background process의 문제를 해결하는 가장 좋은 방법은 stdin, stdout, stderr를 다른 곳으로 redirect시키는 것이다.
unix file은 일련의 permission
을 가지고 있어 사용자가 해당 file에 대한 read
, write
, run
을 실행할 수 있는 권한이 있는 지 없는 지 검사한다. ls -l
을 사용하면 permisstion이 다음과 같이나온다.
-rw-r--r--1 1 juser somegroup 7041 Mar 26 19:34 endnotes.html
-rw-r--r--1
이 바로 file의 mode인데, file의 permission과 추가적인 정보를 표현한다. 여기에는 mode에 대한 4가지 part들이 있는데, 다음과 같다.
첫번째 문자는 file type
이다. -
는 regular file이라는 의미이고, 딱히 특별할게 없다는 것이 binary 또는 text data라는 것이다. 만약, directory였다면 d
가 써있게 된다.
나머지 부분들을 3개씩 3개의 부분으로 나눌 수 있는데, rw-
은 user permission에 관련된 것이고, r--
는 group permission, r--
은 다른 이들을 위한 permission에 관한 것이다.
permission에서 각 문자들이 나타내는 것들은 다음과 같다.
r
: file을 읽을 수 있다.x
: file이 executable이다. 즉, 실행시킬 수 있다.-
: 특별한 것은 없다. 더 구체적으로 보면 해당 slot에 대해서 할당받은 것이 없다.첫번째 부분인 user permission은 file을 소유한 user에 대한 것이다. 위의 예제를 보면 해당 파일은 juser
의 것이다. 두 번째 부분은 group permission으로 file의 그룹에 대한 권한이다. 해당 group에 있는 user라면 file에 대한 권한을 누릴 수 있다.
groups
를 통해서 현재 user가 어디 group에 속한지 알 수 있다.
세번째 부분은 system의 다른 이를 위한 부분으로, 앞에서 속하지 못한 이들의 권한이다. 때때로 이를 world
permission이라고 한다.
일붖 executable file들은 x
가 아니라 s
user permission을 가진다. 이는 해당 executable이 setuid
라는 것으로, 해당 Program을 동작시키면 file을 소유한 사람이 동작시킨 것처럼 동작시킨다. 상당히 많은 program들이 setuid
를 root
로 하여 root
유저의 특권을 가져 system file들을 변경하도록 한다. 가장 대표적인 예로 passwd
가 있는데, 이는 password를 바꾸기 위해서 root만 접근 가능한 system file인 /etc/passwd
file을 수정한다.
즉, root
가 아니여도 root
의 uid로 root
가 동작하는 것처럼 process를 동작시키는 것이다.
file이나 directory의 permission을 변경할 수도 있는데, chmod
를 사용하면 된다. chmod
를 사용할 때, 위에서 나왔던 permission의 영역(user, group, other) 중 하나를 고른 다음에 권한(r, w, x)를 수정하면 된다.
가령, group(g
)과 ohter(o)에게 read(
r`) 권한을 주고 싶다면 다음과 같이 쓸 수 있다.
$ chmod g+r file
$ chmod o+r file
위의 명령어르 하나로 합칠 수도 있다.
$ chmod go+r file
만약 permission을 일부 없애고 싶다면 +
가 아니라 -
로 쓰면 된다.
$ chmod go+r file
이렇게, r
, w
, x
에 대한 권한을 바꾸는 것은 사실 bit를 바꾸는 것이다. 가령 000
에서 read
권한이 추가되면 100
이 되고, write
권한이 추가되면 110
, execute
권한이 추가되면 111
이 되는 것이다. 그렇다면 다음과 같이 숫자로 표현이 가능하다.
$ chmod 644 file
잘보면 굉장히 쉽다. user
section은 6=(110)
이고 group
과 other
은 100
이라는 것이다. 즉, user만 read, write권한이 있고, group과 나머지 유저들은 read권한이 있다는 것이다.
이러한, 변경 방법을 absolute
change라고 하는데, 모든 permission bit를 한 번에 수정하는 것이다.
Mode | Meaning | Used for |
---|---|---|
644 | user: read/write; group, other: read | files |
600 | user: read/write; group, other: none | files |
755 | user: read/write/execute; group, other: read/execute | directories, programs |
700 | user: read/write/execute; group, other: none | directories, programs |
711 | user: read/write/execute; group, other: execute | directories |
directory 역시도 permission을 가지는데, directory에 대한 read
권한이 있어야 directory의 안의 content들에 대해 접근이 가능하다. 그런데, 많은 사람들이 실수하는 것 중 하나가 바로 실행 권한인데, directory에 대한 실행 권한이 없으면 file에 접근이 불가능하다.
https://superuser.com/questions/168578/why-must-a-folder-be-executable
symbolic link
는 하나의 file인데, 다른 file 또는 directory를 참조하고 있는 file이라고 생각하면 된다. 즉, 하나의 alias와 같다. 프로그래밍 언어에서 pointer나 레퍼런스 변수를 생각하면 이해가 쉽다. 다른 객체(file, directory)를 참조하고 있기 때문에, 참조한 file, directory에 변화가 생기면 자신이 영향을 받는 것이다.
symbolic link file은 다음과 같이 생겼다. file type을 나타내는 앞부부인 l
인 것을 유념해두도록 하자.
lrwxrwxrwx 1 ruser users 11 Feb 27 13:52 somedir -> /home/origdir
somedir
directory에 접근하게되면 system은 /home/origdir
로 연결해준다. 재밌는 것은 실제로 /home/origdir
이 없어도 된다. 만약 /home/origdir
이 없는 상태에서 somedir
로 접근하게되면 error가 발생할 뿐 큰 문제가 생기진 않는다. 다만 ls
로 확인할 때는 /home/origdir
이 없어도 연결된 모양으로 나오기 때문에 오히해서는 안된다.
symbolic link
의 가장 큰 문제는, 현재의 symbolic link
가 가리키고 있는 target
이 실제 file인지 directory인지 모른다는 것이다. 즉, symbolic link
를 따라갔더니, 또 symbolic link
가 나올 수 있는 것이다. 이는 chained symbolic link
가 가능하기 때문에 발생하는 문제인 것이다.
symbolic link
를 만들기 위해서는 -s
명령어를 사용하면 된다. target
을 링킹하는 linkname
symbolic link를 만들어보도록 하자.
$ ln -s target linkname
linkname
argument는 symbolic link 이름으로 target
은 특정 file, directory에 대한 path이다. 문제는 이 순서를 많은 사람들 헷갈려해서 target
과 linkname
을 바꾸어 쓰는 경우들이 많다. 다시 정확히 말하자면 target
을 가리키는 linkname
symbolic link file을 만들라는 것이다.
이렇게만 말하면 symbolic link
를 쓰지 말라는 것처럼 보이지만, 사실 굉장히 다양하고 많이 쓰인다. symbolic link
는 다른 file, directory를 불필요하게 복사하지 않기 때문에 굉장히 효율적으로 file, directory에 대한 링크를 제공할 수 있다. 따라서, 복제본을 만들기 싫거나, 또는 해당 file, directory를 변경할 일이 없다면 symbolic link를 사용하는 것을 추천한다.
gzip
은 gnu zip으로 가장 많이 쓰이는 unix 압축 program이다. .gz
확장자로 끝나는 file을 GNU zip archive라고 부르며, gunzip
을 통해서 .gz
file의 압축을 해제할 수 있다.
gzip
은 아쉽게도 file에 대한 archive를 제공해도, file들에 대한 archive를 제공하진 않는다. 즉, 여러 file들과 directory들을 단일 file로 묶어내어 압축하지 못한다는 것이다. 이러한 것을 가능하게 해주는 것이 바로 tar
이다.
$ tar -cvf archive.tar file1 file2 ...
file1
, file2
를 하나의 archive.tar
파일로 묶어내라는 것이다. 주의할 것은 tar
는 여러 file, directory를 하나의 file로 묶어낼 뿐이지, 압축하진 않는다.
c
: create flag로 아카이브 파일을 만들어낸다.v
: verbose flag로 tar가 동작되는 자세한 로그들을 보여준다.f
: file명을 지정한다. 그래서 tar cvf
다음으로 archive.tar
가 나온 것이다.참고로, .tar
파일 확장자는 convention이지 필수는 아니다.
tar파일을 풀어내는 방법은 c
(create)에서 x
(extract)를 하면된다. 즉 unpack인 것이다.
$ tar -xvf archive.tar
단, x
를 통해 extract(unpack)한다고 해서 타겟이 된 .tar
을 unpack 후 삭제하진 않는다.
tar
에는 z
옵션으로 gzip
을 호출할 수 있다. 따라서 기존의 위 옵션 맨 앞에 z
를 붙여서 tar archive 파일을 압축, 압축 풀기를 할 수 있다. 위에서도 언급했지만, tar
는 압축을 하는 동작이 default가 아니라, 여러 file, directory들을 하나의 file로 묶어내는 것이 전부이고, 압축, 압축풀기는 gzip
의 몫이다.
tar -zcvf archive.tar.gz file1 file2 ...
file
이 아니라 directory여도 문제가 없다.
tar -zxvf archive.tar.gz
아마 맨날 헷갈리는 명령어가 될텐데, 위의 역사와 동작을 알고나면 아주 쉬운 명령어이다.
.tgz
file은.tar.gz
과 동일하다. 따라서,tar
를 통해서.tgz
file 압축, 압축 풀기가 가능하다.
linux system directory 구조는 FHS(Filesystem Hierarchy Standard) 구조 윤곽을 가진다.
아래 그림은 linux directory 하위 계층 구조를 보여준다.
root(/
)아래의 하위 directory들은 다음과 같다.
/bin
: 실행 가능한 program(executables)을 가진다. 대표적으로 ls
, cp
와 같은 가장 기본적인 unix 명령어를 포함하고 있으며, 주로 C compiler에 의해 컴파일된 binary가 있다. 단, 최근 modern system에서는 shell script도 포함한다./dev
: device file들을 포함한다. 이에 대해서는 뒤에 더 자세히 다루도록 하자./etc
: core system configuration 디렉터리로 user password, boot, device, networking과 다른 setup file들을 가진다. /home
: home(personal) directory로 일단 user를 위해 존재한다. /lib
: library
를 의미한는 것으로 실행가능한 code를 포함한 library file들을 가진다. library는 정적 라이브러리(static
)와 동적 라이브러리(dynamic
, shared
)가 있는데, /lib
은 오직 shared library
들만을 가진다. /usr/lib
에는 static library와 shared library 모두 가진다./proc
; 해당 directory 내부에는 동작중인 process에 관한 정보들과 kernel parameter들에 대한 정보들을 가진다. /run
: system에 대한 runtime data를 가진다. 이 data에는 특정한 process ID, socket file, status record, system logging 등을 가진다. 예전 system에서는 /run
이 아니라 /var/run
이지만, 요즘은 /run
으로 변경되었고, /var/run
은 /run
에 대한 symbolic link가 되었다./sys
: /sys
directory는 device와 system interface를 제공한다는 점에서 /proc
과 비슷하다. 이에 대해서는 추후에 알아보도록 하자./sbin
: system 실행 파일들이 있는 장소로, /sbin
directory에 있는 program들은 system 관리와 관련이 깊다. 따라서 일반 유저들은 /sbin
component를 가지지 않는다./tmp
: 신경쓰지 않아도되는 작고, 일시적인 file들을 보관하는 storage 공간이다. linux user들은 /tmp
에 대한 read, write 권한이 있어 얼마든지 자신의 file들을 /tmp
에 만들어낼 수 있다. 단, 다란 user가 만든 file에 관해서는 /tmp
에 있다하더라도 접근할 수 없다. 대부분의 program들은 /tmp
를 workspace로서 사용하고 있다. 단, /tmp
는 system이 재부팅되면 싹 cleanup되는 directory이므로 중요한 data를 담고있지 않아야 한다. /usr
: user
라고 발음하지만 이 하위 directory에는 user에 관한 file이 없다. /usr
에는 linux system의 대부분을 포함하는 대규모 directory 계층 구조가 포함되어 있다. /usr
에는 root
directory 시스템 계층처럼 /usr/bin
, /usr/lib
directory와 같은 것들이 있으며, 동일한 type의 file을 가진다. 이는 과거에 root 공간을 낮게 유지하기 위해 디자인하여 이렇게 된 것이다./var
: program이 시간이 지남에 따라 변경될 수 있는 정보를 기록하는 variable 하위 directory이다. system logging, user tracking, caches, system program 만들거나, 관리하는 여러 file들이 바로 이 directotry에 있다. 몇 가지 재미난 subdirectory들이 더 있다.
/boot
: kernel boot loader file들이 존재한다. /meida
: 연결될 media들을 위한 directory로 하나의 attachment를 제공하는 것이다. 가령 flash drive가 같은 것들이 연결되면 /media
로 연결된다고 생각하면 된다. 연결이 끊어지면 media도 삭제 가능하다./opt
:이 directory는 추가적인 제 3자 software를 포함하는데, 많은 system들은 /opt
를 잘 안사용한다. /usr
은 data가 있는 user space program을 담당한다. /usr
내부에는 다음의 명령어들도 존재하는 거라고 생각하면된다.
/include
: C compiler에게서 사용되는 사용되는 header file들을 가지고 있는다. /local
: 관리자가 그들 자신의 software를 설치할 수 있는 정소, 이곳의 구조는 /
와 /usr
와 같다./share
: 다른 종류의 unix system에서도 작동해야하는 file이 포함되어있다. 이는 일반적으로 program과 library가 필요에 따라 읽는 보조 데이터 파일인 것이다.