ps 명령어는 프로세스 상태, PID, 메모리 및 CPU 사용량 등의 정보를 제공하며, 시스템에서 실행 중인 작업을 모니터링하거나 디버깅할 때 유용하다.
ps
기본적으로 ps 명령어를 실행하면 현재 터미널에 연결된 프로세스 목록을 출력한다.
기본 출력에는 다음과 같은 정보가 포함된다.
PID: 프로세스 ID
TTY: 프로세스가 연결된 터미널
TIME: 프로세스가 사용한 CPU 시간
CMD: 실행된 명령어 이름
모든 프로세스 목록 출력
ps -e
프로세스의 상세 정보 출력 (PID, PPID, UID, 시작 시간 등 포함)
ps -f
현재 쉘 세션의 프로세스 정보를 확인
ps $$
ps $$ 명령어는 현재 사용 중인 쉘 세션의 프로세스 정보를 확인하는 간단한 방법이다. 이를 통해 현재 쉘의 PID와 상태를 확인할 수 있다.
모든 프로세스의 상세 정보 출력 (주로 시스템 상태를 전체적으로 확인할 때 사용)
ps -ef
특정 프로세스의 PID 찾기
ps -ef | grep apache
paralle+는 프로세스를 실행한 사용자를 의미한다. 여기서는 “parallels” 사용자가 grep 명령을 실행했음을 의미한다. (+는 이름이 길어서 잘린 것).
4577은 해당 프로세스의 PID(프로세스 ID)이다.
0.0은 CPU 사용률을, 0.1은 메모리 사용률을 나타낸다.
4344는 프로세스의 가상 메모리 크기(KB)이고, 2084는 물리 메모리 크기(RSS)이다.
pts/1은 프로세스가 연결된 터미널을 나타낸다.
R+는 프로세스의 상태를 의미하며, 여기서는 Running(실행 중)을 나타낸다.
21:38는 프로세스가 시작된 시각이다.
0:00은 프로세스가 CPU에서 사용한 총 시간이다.
grep --color=auto apache는 실행된 명령어를 나타낸다.
현재 apache라는 이름의 실제 프로세스가 실행되고 있지 않음을 의미한다. grep 자체가 검색한 내용을 출력한 것이기 때문에, 진짜 apache 프로세스가 실행 중인지 확인하려면, ps aux | grep apache | grep -v grep 명령을 사용하여 grep 명령 자체를 제외하고 확인할 수 있다.
ps aux | grep apache | grep -v grep
CPU 사용률 기준 상위 10개 프로세스 보기
ps aux --sort=-%cpu | head -n 10
프로세스 종료
kill 명령어는 프로세스에 시그널(Signal)을 보내기 위해 사용된다.
기본적으로 프로세스를 종료하는 데 자주 사용되지만, 특정 시그널을 지정하여 프로세스를 일시 중단하거나, 다시 시작하는 등의 작업도 수행할 수 있다.
kill [옵션] <PID>
<PID>는 시그널을 보낼 프로세스의 ID(프로세스 ID)이다. 기본적으로 kill 명령어는 SIGTERM(15) 시그널을 보낸다. 이 시그널은 정상 종료를 요청하는 시그널로, 프로세스가 종료 전에 필요한 정리 작업을 수행할 수 있다.
kill -l : 사용 가능한 시그널 목록을 출력한다.
kill -s <시그널 이름> <PID> : 특정 시그널 이름을 지정하여 프로세스에 보낸다.
kill -<시그널 번호> <PID> : 시그널 번호로 지정하여 프로세스에 보낸다.
특정 프로세스 종료 (SIGTERM 사용)
kill 1234
프로세스 ID가 1234인 프로세스에 SIGTERM 시그널을 보내 정상 종료를 요청한다.
강제 종료 (SIGKILL 사용)
kill -9 1234
# 또는
kill -SIGKILL 1234
# 또는 SIG 생략
kill -KILL 1234
특정 시그널 지정하여 전송 (예: SIGHUP)
kill -HUP 1234
# 또는
kill -1 1234
SIGHUP(1) 시그널은 프로세스를 다시 로드하거나 재시작하도록 알린다. 주로 설정 파일이 변경된 경우 설정을 다시 적용하는 데 사용된다.
특정 포트번호를 사용하는 프로세스를 찾고, 종료
sudo lsof -i :8080
이 명령은 8080번 포트를 사용 중인 프로세스를 찾는다.
출력에는 프로세스 이름, PID, 사용자, 프로토콜 등의 정보가 포함된다.
kill -9 23204
# 또는
kill -SIGKILL 23204
# 또는 SIG 생략
kill -KILL 23204
# 또는 정상 종료 요청
kill 23204
Background, Foreground
백그라운드에서 프로세스 실행
명령어 끝에 &를 붙이면 해당 프로세스가 백그라운드에서 실행된다.
sleep 10 &
포그라운드에서 실행 중인 프로세스를 백그라운드로 전환
프로세스 일시 정지: Ctrl + Z를 눌러 포그라운드 프로세스를 일시 정지한다. 이로 인해 프로세스가 Stopped 상태가 된다.
백그라운드로 전환: bg 명령어를 입력하면, 일시 정지된 프로세스가 백그라운드에서 계속 실행된다.
리눅스 시스템 부팅 시 커널이 가장 먼저 생성하는 프로세스로, 메모리 관리 및 시스템 초기화 같은 커널 수준의 작업을 담당한다.
시스템 부팅 중 커널의 초기화를 수행.
이후 사용자 영역의 첫 프로세스인 프로세스 1(init)을 생성.
모든 초기화가 완료되면, Idle Process로 전환되어 CPU의 유휴 상태를 관리.
PID 0이며, 사용자 영역에서는 보이지 않으며 커널 내부에서만 존재.
PID (Process ID) : 프로세스를 고유하게 식별하는 번호, 부모 프로세스와 자식 프로세스를 연결하는 데 사용. PPID (Parent Process ID) : 부모 프로세스의 PID를 나타냄. UID (User ID) : 프로세스를 실행한 사용자의 ID. GID (Group ID): 프로세스를 실행한 사용자가 속한 그룹의 ID.
Process 1 (Init 또는 Systemd)
프로세스 0이 사용자 공간에서 실행할 첫 프로세스로 생성하는 프로세스이다.
리눅스 시스템에서 다른 모든 사용자 프로세스의 최상위 부모 프로세스가 된다.
파일 시스템 마운트, 네트워크 설정, 데몬 프로세스 실행.
자식 프로세스 생성 및 종료 상태 처리.
시스템 종료와 재부팅 관리.
PID 1이며 사용자 영역의 첫 번째 프로세스.
현대 리눅스에서는 init 대신 systemd가 이 역할을 수행.
모든 프로세스는 최초 프로세스(init 또는 systemd)를 기점으로 계층적으로 연결된다.
고아 프로세스와 좀비 프로세스
부모 프로세스의 역할
부모 프로세스는 fork() 시스템 호출을 통해 자식 프로세스를 생성하는 프로세스이다.
모든 프로세스는 부모 프로세스를 가지며, 최상위 부모는 init(systemd, PID 1)이다.
부모는 자식 프로세스의 상태를 추적하여 종료 시점에 대한 정보를 확인.
자식 프로세스가 종료되면 부모는 wait() 또는 waitpid()를 호출하여 자식의 종료 상태(exit code)를 수집.
자식 프로세스가 종료되면 부모는 자식의 PCB(Process Control Block) 및 기타 자원을 회수해야 한다.
프로세스 종료 상태(Exit Status)
프로세스 종료 상태(Exit Status)는 리눅스 및 유닉스 운영체제에서 프로세스가 종료되었을 때, 부모 프로세스에게 반환하는 값이다.
이 값은 프로세스의 성공 또는 실패 여부와 종료 원인 등을 나타내며, 디버깅 및 시스템 관리에 중요한 정보를 제공한다.
종료 상태는 0~255 사이의 정수값으로 반환된다.
0: 정상 종료(Success).
0이 아닌 값: 비정상 종료(Failure) 또는 특정 오류 코드.
시그널(Signal)을 받아서 종료되었는지 여부 및 시그널의 종류, 코어 덤프(core dump)를 생성했는지 여부도 포함
* 코어 덤프(Core Dump)는 프로그램이 비정상적으로 종료되었을 때, 해당 시점의 메모리 상태, CPU 레지스터 값, 프로세스의 실행 정보를 저장한 파일이다.
자식 프로세스가 종료되면 종료 상태는 부모 프로세스에 전달된다.
부모는 wait() 또는 waitpid()를 호출하여 자식의 종료 상태를 수집한다.
고아 프로세스(Orphan Process)
고아 프로세스는 부모 프로세스가 종료되었음에도 자식 프로세스가 계속 실행 중인 상태를 말한다.
즉, 프로세스가 종료되면 PCB 및 기타 자원을 회수해주어야할 부모 프로세스가 있어야하는데, 자식 프로세스가 종료되기 전에 부모 프로세스가 먼저 종료된 상태를 뜻한다.
부모가 먼저 종료되면 자식은 부모 프로세스를 init 프로세스(PID 1)로 재설정하게 된다.
예시 1. A 프로세스가 B 프로세스를 생성했으나, A 프로세스가 예상보다 빨리 종료됨. 2. B는 여전히 작업 중이며, 이 상태에서 B는 고아 프로세스가 됨. 3. 커널은 B의 부모를 init 프로세스로 변경하여 관리.
좀비 프로세스(Zombie Process)
좀비 프로세스는 프로세스 실행이 종료되었지만, 부모 프로세스가 자식의 종료 상태를 수집하지 않아 PCB 및 기타 시스템 자원이 시스템에 남아 있는 상태를 말한다.
프로세스가 종료되면 커널은 종료 코드를 보존하고, 부모가 이를 회수(wait() 호출)할 때까지 PCB를 유지한다.
부모가 회수하지 않으면 좀비 프로세스가 계속 남아 있어 시스템 리소스를 낭비하게 된다.
<해결 방법>
부모 프로세스가 wait() 또는 waitpid()를 호출하여 자식의 종료 상태를 회수해야 함.
부모 프로세스가 좀비 상태를 방치하면, 부모 프로세스를 강제 종료하여 자식을 고아 프로세스로 만들어 init 프로세스가 회수하게 함.
표준 스트림과 파일 디스크립터
리눅스는 모든 입출력 작업을 파일로 추상화하여 처리한다.
표준 스트림은 프로그램 실행 시 기본적으로 제공되는 입출력 경로를 의미하며, 파일 디스크립터는 이러한 입출력 대상(파일, 소켓, 파이프 등)을 식별하기 위한 정수이다.
표준 스트림(standard streams)
표준 스트림은 프로세스가 입출력 작업을 수행하기 위해 기본적으로 제공되는 세 가지 스트림이다.
프로세스 실행 시 자동으로 생성되며, 각각 고유의 역할을 가진다.
이름
파일 디스크립터 번호(FD)
설명
표준 입력 (stdin)
0
사용자의 입력을 받아들이는 스트림
표준 출력 (stdout)
1
프로그램의 실행 결과를 출력하는 스트림
표준 에러 (stderr)
2
에러 메시지를 출력하는 스트림
표준 입력 : 기본적으로 키보드로 입력하는 것을 뜻함
표준 출력 : 실행 결과가 모니터로 출력되는 것을 뜻함
표준 에러 : 에러 메시지가 출력되는 것을 뜻함
파일 디스크립터(file descriptor)
파일 디스크립터는 리눅스와 같은 운영체제에서 파일이나 입출력 장치(예: 키보드, 모니터)를 다루기 위한 숫자 식별자이다.
이 숫자는 프로세스가 열어놓은 파일이나 장치에 접근할 때 사용되며, 일종의 ID 번호라고 생각하면 된다.
컴퓨터는 모든 입출력을 파일로 취급한다. 예를 들어, 키보드 입력이나 화면 출력도 사실상 파일처럼 다룬다. 파일 디스크립터는 프로그램이 이러한 파일(혹은 입출력 장치)을 가리키고 사용하는 번호표이다.
파일에 대한 작업(읽기/쓰기)을 하기 위해서는 파일 디스크립터를 열어야 한다.
프로세스로 열린 파일 디스크립터 목록을 관리한다.
* “프로세스로 열린 파일 디스크립터 목록을 관리한다”는 말은, 각각의 프로세스(즉, 실행 중인 프로그램)가 자신이 열어놓은 파일이나 장치의 목록을 운영체제에서 따로따로 관리한다는 뜻이다.
* 프로그램(프로세스)이 실행되면서 여러 파일을 열거나 장치에 접근할 때, 운영체제는 각 프로세스마다 어떤 파일을 열었는지 목록을 기억해둔다. 이를 통해 프로세스가 필요할 때 열어둔 파일에 쉽게 접근할 수 있고, 프로그램이 끝날 때 열린 파일을 자동으로 닫아주는 관리가 가능하다.
Foreground, Background, Daemon Process
Foreground Process
Foreground Process는 사용자가 터미널에서 직접 실행하고 제어하는 프로세스이다.
사용자가 실행을 시작하면, 이 프로세스는 터미널에 입력과 출력을 독점하며, 사용자가 해당 프로세스가 종료되거나 중단될 때까지 터미널은 다른 명령을 받지 않는다.
쉘의 표준 입력이 연결된 프로세스
표준 출력과 표준 에러도 쉘과 연결되어 있음
사용자가 직접 실행하고, 종료되기 전까지 터미널은 해당 프로세스에 점유된다.
프로세스의 입력과 출력이 모두 터미널을 통해 이루어진다.
사용자는 한 번에 하나의 전경 프로세스만 제어할 수 있다.
Background Process
Background Process는 사용자가 터미널에서 실행했지만, 실행되는 동안 터미널을 점유하지 않는 프로세스이다.
즉, 프로세스가 실행되는 동안에도 사용자는 터미널에서 다른 명령을 입력하고 작업을 수행할 수 있다.
백그라운드 프로세스는 일반적으로 사용자와 상호작용하지 않으며, 필요할 경우 백그라운드에서 계속 작업을 진행한다.
쉘의 표준 입력이 연결되지 않은 프로세스
표준 출력과 표준 에러는 쉘과 연결되어 있음
터미널에 입력과 출력이 독립적으로 이루어진다.
프로세스는 터미널에서 독립적으로 실행되며,&를 붙여 실행하거나bg명령으로 백그라운드로 전환할 수 있다.
여러 개의 백그라운드 프로세스를 동시에 실행할 수 있다.
Daemon Process
Daemon Process는 백그라운드에서 지속적으로 실행되며, 시스템 서비스나 특정 작업을 수행하는 프로세스이다.
일반적인 백그라운드 프로세스와 달리, 데몬 프로세스는 터미널과 완전히 분리되어 시작되며, 시스템 시작 시 자동으로 실행되거나 특정 서비스의 요청을 처리하기 위해 상시 대기한다.
주로 서버, 네트워크 관리, 시스템 유지 보수 등의 기능을 수행한다.
백그라운드 프로세스로 동작하기 위해 만들어진 프로세스
표준 스트림을 갖고 시작하지만 모두 닫아버리기 때문에 쉘과 입출력 교환이 불가하다.
부모 프로세스를 init(또는 systemd) 프로세스로 변경
시그널(Signal)
시그널은 비동기(Asynchronous) 이벤트를 처리하기 위한 프로세스간 통신이라고 말할 수 있다.
쉽게 말하면, 시그널(Signal)은 리눅스와 유닉스 시스템에서 프로그램에 특정 이벤트가 발생했음을 알리기 위한 알림 메시지(인터럽트)라고 생각하면 된다.
시그널을 통해 시스템은 프로세스(프로그램)에게 이벤트를 알려주고, 프로그램은 이 신호를 받아서 특정 작업을 하거나 종료할 수 있다.
시그널과 비동기 방식은 프로그램에서 예기치 않게 발생하는 일을 즉각적으로 처리하는 데 사용된다.
각각 다른 개념이지만, 둘 다 작업의 흐름을 방해하지 않으면서 알림이나 작업을 처리할 수 있도록 돕는다.
비동기 방식은 작업을 요청한 후 그 작업이 끝날 때까지 기다리지 않고 다음 일을 계속하는 방식이다.
비동기 방식에서는 결과를 기다리지 않고 다른 작업을 먼저 처리할 수 있다.
시그널이 발생하는 것은 그림에서 클라이언트가 서버로 요청을 보내는 것과 비슷하다.
시스템(클라이언트)은 프로세스(서버)에게 이벤트 내용을 시그널을 통해 비동기적으로 보낸다.
비동기 방식이기 때문에 프로그램은 시그널 요청을 받고도 계속해서 원래 하던 작업을 유지할 수 있다.
그러나 시그널이 발생하면 이 요청에 대한 응답(즉, 시그널 처리를 위한 코드 실행)을 예약해 두거나 준비하게 된다.
시그널이 발생한 후, 프로그램이 준비가 되었을 때 시그널 핸들러(Signal Handler)를 통해 시그널을 처리한다.
이 과정에서 프로그램은 시그널을 처리하면서 “필요한 일을 수행하고”(예: 로그 작성, 작업 중단 등) 다시 원래 작업으로 돌아가게 된다.
시그널의 비동기적 방식 요약 1. 시그널은 프로세스가 어떤 작업을 하고 있는지와 상관없이 발생할 수 있다. 2. 시그널은 프로세스가 언제든지 받을 수 있고, 시그널이 발생하면 프로세스는 즉시 시그널을 받게 된다. 하지만 비동기적 방식이기 때문에, 시그널을 받은 후에도 기존 작업을 중단하지 않고 필요에 따라 시그널을 처리할 시점을 결정할 수 있다. 3. 이후 프로그램은 시그널에 대한 응답(시그널 핸들러 실행)을 통해 시그널을 처리하고 필요한 동작을 수행하게 된다.
루트 디렉토리(/)를 최상위 디렉토리로 시작하여 그 아래에 다양한 디렉토리와 파일들이 존재한다.
대표적인 디렉토리는 다음과 같다
/bin: 일반 사용자와 관리자 모두가 사용하는 기본 명령어가 포함된 디렉토리이다. ls, cp 등과 같은 시스템 명령어가 여기에 위치한다.
/sbin: 시스템 관리자 권한으로 실행해야 하는 실행 파일 위치한다.
/boot: 시스템 부팅에 필요한 파일을 포함하며, 커널과 관련된 파일들이 저장된다.
/dev: 디바이스 드라이버가 사용하는 디바이스 파일 디렉터리. 시스템의 모든 장치 파일들이 존재한다.
/etc: 시스템과 관련된 주요 설정 파일들이 위치하는 디렉토리로, 사용자 계정 정보, 네트워크 설정 파일 등이 저장된다.
/home: 사용자의 홈 디렉토리로, 사용자별로 개인 파일 및 설정 파일이 저장된다.
/lib: 시스템 실행에 필요한 라이브러리 파일들이 포함된다.
/mnt와 /media: 외부 저장 장치를 임시로 마운트할 때 사용된다.
/proc: 프로세스와 시스템 상태 정보가 저장된 가상 파일 시스템으로, 현재 실행 중인 프로세스 정보를 확인할 수 있다.
/sys: 하드웨어 장치와의 상호작용 및 설정을 지원하는 가상 파일 시스템으로, 동적 장치 인식 및 관리가 가능하다.
/tmp: 임시 파일들이 저장되는 공간으로, 시스템 재부팅 시 삭제된다.
/usr: 사용자 프로그램과 유틸리티가 저장되며, 서브 디렉토리로 bin, lib, include 등이 있다.
/var: 가변 데이터를 저장하는 디렉토리로, 로그 파일이 주로 저장되는 /var/log가 여기에 포함된다.
마운트
리눅스에서 마운트(Mount)는 외부 장치나 파일 시스템을 리눅스 디렉토리 구조에 연결하여 접근할 수 있도록 하는 과정이다.
마운트를 통해 USB 드라이브, 외장 하드, 다른 파티션 등의 파일 시스템을 리눅스의 특정 디렉토리 경로에 연결하여 사용자가 파일을 읽고 쓸 수 있게 된다.
리눅스의 파일 시스템은 통합된 디렉토리 구조를 사용하므로, 새 장치를 마운트하면 파일 시스템 어디서든지 접근이 가능하다.
마운트의 기본 개념
리눅스에서 마운트는 특정 장치를 디렉토리 구조의 특정 위치에 연결하여 데이터를 접근할 수 있게 한다. 리눅스에서는 장치가 연결된 경로(/dev/sda1 같은 장치 파일 경로)를 지정하고, 이를 디렉토리 경로(예: /mnt/usb)에 마운트한다. 마운트된 후에는 일반 디렉토리처럼 장치의 파일에 접근할 수 있다.
예를 들어, /dev/sdb1 장치를 /mnt/usb에 마운트하려면 다음과 같이 명령한다.
mount /dev/sdb1 /mnt/usb
리눅스의 마운트 시스템은 Windows나 다른 운영체제와 차이가 있으며, 특히 파일 시스템 접근 방식과 마운트 관리에서 여러 독특한 특징이 있다. 이를 비교해 보자.
마운트 방식의 차이점
리눅스와 유닉스 계열: 리눅스에서는 파일 시스템 구조가 단일 트리 구조로 구성된다. 모든 장치나 파티션은 루트 디렉토리(/) 아래에 마운트된다. 예를 들어, USB 드라이브를 /mnt/usb 같은 특정 디렉토리에 마운트하면, /mnt/usb 디렉토리를 통해 USB 드라이브에 접근할 수 있다. 이 구조는 운영체제의 모든 파일을 하나의 통일된 파일 시스템 트리 아래에서 관리할 수 있게 해준다.
Windows: Windows에서는 드라이브 문자를 사용하여 파일 시스템을 분리하여 표시한다. 예를 들어, 기본 디스크는 C: 드라이브로, 외장 드라이브는 D:, E: 등의 드라이브 문자로 나타난다. 이처럼 파일 시스템이 드라이브 문자로 분리되어 있으며, 각 드라이브는 독립된 경로로 접근한다. Windows에서는 하나의 디렉토리 트리로 통합되지 않고, 각 드라이브가 개별적으로 존재하는 형태이다.
마운트 설정과 관리의 차이점
리눅스: 리눅스에서는 mount 명령어를 사용하여 장치를 특정 디렉토리에 마운트하고, 필요시 umount 명령어로 마운트를 해제한다. 또한, /etc/fstab 파일을 통해 부팅 시 자동으로 마운트할 장치를 설정할 수 있으며, 다양한 옵션을 통해 파일 시스템의 동작 방식을 세밀하게 조정할 수 있다. 리눅스는 파일 시스템의 자동 마운트, 동기화 설정, 파일 접근 권한 등 다양한 옵션을 제공하여 서버 환경에서 더욱 유연하고 세밀한 마운트 관리를 가능하게 한다.
Windows: Windows에서는 일반적으로 USB나 외장 하드 등을 연결할 때 자동으로 드라이브 문자를 할당하여 마운트한다. 사용자에게 명시적으로 마운트를 요구하지 않으며, 외장 장치를 제거할 때도 ‘안전하게 제거’ 절차를 통해서만 해제된다. 부팅 시 자동 마운트 설정을 관리하려면 디스크 관리 도구를 통해서 하거나 레지스트리를 수정해야 하므로, 리눅스의 /etc/fstab 같은 직접적인 파일 설정 방식이 없다.
파일의 종류
일반 파일(regular file) : 말 그대로 일반 파일. 텍스트 파일이나 동영상 파일 등이 일반 파일에 포함
디렉터리(directory) : 디렉터리도 파일의 한 종류. 윈도우의 폴더와 같은 개념
심볼릭 링크 파일(symbolic link file) : 어떤 다른 파일을 가리키는 파일. 윈도우의 바로가기와 같은 개념
블록 디바이스 파일(block device file) : 블록 디바이스를 제어하기 위한 파일
문자 디바이스 파일(character device file) : 문자 디바이스를 제어하기 위한 파일
파이프 파일(pipe file) : 파이프를 나타내는 파일. 프로세스간 통신(IPC)에 사용됨
소켓(socket) : 소켓을 나타내는 파일. 프로세스간 통신(IPC)에 사용됨
디바이스 드라이버, 디바이스 파일(블록 및 문자 디바이스 파일)
디바이스 드라이버
디바이스 드라이버는 운영체제와 하드웨어 간의 통신을 담당하는 소프트웨어이다.
운영체제가 하드웨어 장치와 직접 통신하는 대신, 디바이스 드라이버를 통해 명령을 전달하고 결과를 받는다.
드라이버는 하드웨어의 특성을 이해하고, 운영체제와 장치 간에 필요한 데이터를 적절한 형식으로 변환하는 역할을 한다.
네트워크, 그래픽, USB 드라이버 등이 있다.
디바이스 파일
디바이스 파일은 리눅스에서 하드웨어 장치를 파일처럼 취급하여 접근할 수 있게 해주는 특수 파일이다.
리눅스 시스템에서는 모든 장치가 /dev 디렉토리에 디바이스 파일 형태로 존재하며, 이를 통해 응용 프로그램이나 사용자가 장치에 접근할 수 있다.
디바이스 드라이버와 디바이스 파일의 상호작용
디바이스 드라이버는 하드웨어와 운영체제 간의 중개 역할을 담당하며, 디바이스 파일은 이 드라이버와의 통신을 위해 사용자가 접근할 수 있는 인터페이스를 제공한다.
사용자가 디바이스 파일에 데이터를 읽거나 쓰면, 디바이스 파일이 디바이스 드라이버를 호출하고, 디바이스 드라이버는 이 명령을 해석하여 실제 하드웨어 장치로 전달한다.
예를 들어, 사용자가 /dev/sda에 접근하여 파일을 읽으려 하면, 블록 디바이스 드라이버가 호출되어 하드 디스크에서 해당 데이터를 읽어들인 후 결과를 반환한다.
디바이스 파일은 아래와 같이 블록 디바이스 파일과 문자 디바이스 파일로 나뉜다.
블록 디바이스 파일(block device file) : 블록 디바이스를 제어하기 위한 파일
문자 디바이스 파일(character device file) : 문자 디바이스를 제어하기 위한 파일
하드링크와 소프트 링크
하드링크와 소프트링크에 대해 알아보기 앞서서 아이노드를 알 필요가 있다.
아이노드(i-node)
아이노드(inode)는 리눅스 파일 시스템에서 각 파일이나 디렉토리의 정보를 저장하는 데이터 구조이다.
파일의 실제 데이터(내용)가 저장된 위치가 아니라, 해당 파일에 대한 메타데이터를 담고 있는 공간이라고 할 수 있다.
각 파일이나 디렉토리는 고유한 아이노드 번호를 가지며, 이 번호를 통해 파일 시스템은 파일의 메타데이터를 찾는다.
이렇게 복잡해보이는 그림을 아래와 같이 단순화 시킬 수 있다.
파일 이름: 사용자가 파일을 식별할 때 사용하는 이름으로, 디렉토리 구조에서 파일 이름이 저장된다. 이 파일 이름은 아이노드 번호를 참조하여 파일의 실질적인 위치를 찾는다.
아이노드: 파일의 메타데이터(파일 크기, 권한, 생성 시간 등)를 포함하며, 파일 내용이 저장된 데이터 블록의 위치를 가리키는 정보가 담겨 있다. 즉, 파일 이름은 아이노드를 가리키고, 아이노드는 파일 내용을 가리킨다.
파일 내용: 실제 파일의 데이터가 저장된 블록으로, 아이노드의 정보를 통해 접근된다.
이를 통해 리눅스 파일 시스템은 파일 이름을 통해 간접적으로 파일 내용에 접근하게 된다. 아이노드를 사용하면 하드 링크와 소프트 링크 같은 다양한 파일 참조 방식이 가능해진다.
이 그림은 하드 링크(Hard Link)와 소프트 링크(Soft Link, 심볼릭 링크)가 파일 시스템에서 어떻게 동작하는지를 보여준다.
우리가 컴퓨터에서 파일을 만든다고 생각해보자. 이 파일에는 이름(Filename)이 있고, 실제 파일 내용(File Data)이 저장된다. 파일 시스템에서는 이 파일을 관리하기 위해 아이노드(inode)라는 중간 정보를 사용한다. 아이노드는 파일이 어디에 저장되어 있는지, 크기는 얼마나 되는지 등의 정보만을 담고 있다.
이제 파일을 복사하거나 링크(바로 가기)를 만들 때, 하드 링크와 소프트 링크라는 방식으로 파일을 참조할 수 있다.
하드 링크 (Hard Link) - 같은 파일로 취급
설명: 하드 링크는 원본 파일과 같은 아이노드(inode)를 공유한다. 즉, 원본 파일과 하드 링크는 사실상 같은 파일이다.
특징: 하드 링크를 통해 파일에 접근하면, 원본 파일에 접근하는 것과 동일한 효과가 있다.
삭제 시 특징: 원본 파일이나 하드 링크 중 하나를 삭제해도 남아있는 파일(다른 하드 링크나 원본 파일)을 통해 여전히 데이터에 접근할 수 있다.
예시
한 가지 파일에 서로 다른 이름을 붙여놓은 것과 같다.
예를 들어, 하나의 문서 파일이 있는데, 그 파일을 두 개의 다른 이름으로 저장한다고 상상해보자. 파일 이름은 다르지만 내용은 동일하고, 어느 파일을 수정해도 둘 다 바뀌는 효과가 있다.
하드링크 명령어
하드 링크를 생성하는 명령어는 ln이다.
위 사진과 같이 현재 디렉터리에는 3개의 파일이 있다.
또한 a의 아이노드 값은 20418673이다.
위와 같은 명령어로 하드링크를 만들었다.
다시 확인해보면 같은 아이노드를 가지는 b.txt를 확인할 수 있다.
소프트 링크 (Soft-Link == Symbolic Link == SymLink) - 다른 위치를 가리키는 바로 가기
설명: 소프트 링크는 원본 파일과 다른 아이노드를 가진다. 대신 원본 파일의 경로(위치)만을 저장해 두는 방식이다.
특징: 소프트 링크는 원본 파일의 위치 정보만 가지고 있으므로, 원본 파일이 삭제되거나 이동되면 소프트 링크는 깨진 링크(broken link)가 되어 데이터를 찾을 수 없다.
다른 파일 시스템에서도 사용 가능: 소프트 링크는 파일 시스템을 넘어, 다른 디렉토리나 장치에서도 원본 파일을 참조할 수 있다.
예시
소프트 링크는 우리가 흔히 사용하는 바로 가기와 유사하다.
예를 들어, 데스크톱에 있는 프로그램의 바로 가기를 만든다고 해보자. 실제 프로그램은 다른 폴더에 있지만, 바로 가기를 통해 쉽게 실행할 수 있다. 그러나 원본 프로그램을 삭제하면 바로 가기는 더 이상 작동하지 않는다.
소프트링크 명령어
소프트링크 생성 명령어는 ln 에서 -s 옵션을 주면 된다.
b.txt 라는 소프트링크가 a.txt를 가리키고 있다.
여기서 소프트링크의 경로를 수정하거나 원본 파일의 경로를 수정하면 소프트링크가 깨질 수 있다.
이는 하드링크와 다른점이다.
하드 링크는 원본 파일과 동일한 아이노드(inode)를 공유하기 때문에, 원본 파일의 경로나 이름이 변경되어도 하드 링크는 계속해서 파일 내용을 참조할 수 있다.
하드 링크와 원본 파일은 실제로 동일한 파일 데이터를 가리키고 있기 때문에, 하나의 파일이 삭제되거나 경로가 변경되더라도 다른 하드 링크는 영향을 받지 않는다.
This system has been minimized by removing packages and content that are
not required on a system that users do not log into.
To restore this content, including manpages, you can run the 'unminimize'
command. You will still need to ensure the 'man-db' package is installed.
위 메시지는 시스템이 최소화(minimized)되어 man 페이지와 같은 비필수 패키지 및 콘텐츠가 제거된 상태라는 의미이다. 이러한 최소화된 환경에서는 man 명령어의 설명 페이지가 제공되지 않는다.
아래의 명령어는 최소화된 시스템에서 제거된 콘텐츠를 복원하는 데 사용된다.
sudo unminimize
이렇게 하면 man 페이지를 포함한 문서화가 복원되고 man ls와 같은 명령어를 사용할 수 있게 된다.
man 명령어는 “manual”의 약자로, 리눅스와 유닉스 계열 시스템에서 명령어 및 프로그램에 대한 설명서(manual page)를 표시하는 데 사용된다. 사용자가 명령어의 사용법, 옵션, 인자, 예제 등을 확인할 수 있게 도와준다.
man command_name
command_name 자리에 확인하고자 하는 명령어나 프로그램 이름을 입력하면 해당 명령어의 설명서가 출력된다.
/(슬래시)문자열을 입력하면 원하는 내용을 검색할 수도 있다.
->ex) /help
검색 결과가 여러개일 경우 n을 누르면 다음 검색 결과로 이동한다.
나가려면 q 를 누르면 된다.
파일 목록/내용 조회
ls
ls 명령어는 현재 경로의 디렉토리와 파일을 확인할 수 있는 명령어이다. 기본적으로 ls 명령어를 입력하면 현재 디렉토리에 있는 파일과 디렉토리의 목록이 출력된다.
추가적인 옵션을 사용하면 더 많은 정보를 볼 수 있다.
ls -l: 파일 및 디렉토리의 세부 정보(권한, 소유자, 파일 크기, 수정 날짜 등)를 포함한 목록을 출력한다.
ls -a: 숨김 파일(파일명 앞에 .이 있는 파일 포함)을 포함하여 모든 파일과 디렉토리를 출력한다.
ls -d */: 현재 디렉토리 내의 디렉토리만 출력한다.
cat
cat 명령어는 “concatenate”의 약자로, 파일의 내용을 출력하거나 여러 파일을 결합하여 표시하고, 새로운 파일을 생성할 때 사용된다. 주로 파일의 내용을 빠르게 확인하기 위해 사용된다.
파일 내용 출력
cat filename.txt
여러 파일 결합 및 출력
cat file1.txt file2.txt
여러 파일의 내용을 한 번에 결합하여 출력한다.
파일 내용 결합 후 새로운 파일 생성
cat file1.txt file2.txt > combined.txt
file1.txt와 file2.txt의 내용을 결합하여 combined.txt라는 새로운 파일에 저장한다.
파일에 내용 추가
cat file3.txt >> existing_file.txt
file3.txt의 내용을 existing_file.txt의 끝에 추가한다.
주요 옵션
-n: 출력되는 각 라인에 번호를 붙여서 보여준다.
cat -n filename.txt
-b: 빈 줄을 제외한 각 라인에 번호를 붙인다.
cat -b filename.txt
-s: 연속된 빈 줄을 한 줄로 축소하여 출력한다.
cat -s filename.txt
head 및 tail
head와 tail 명령어는 파일의 내용을 부분적으로 출력할 때 사용하는 명령어이다. 두 명령어 모두 텍스트 파일의 특정 부분을 확인할 때 유용하다.
head
head는 기본적으로 파일의 처음 몇 줄을 출력하는 명령어이다. 기본값으로 처음 10줄을 출력하지만, 옵션을 사용하여 출력할 줄 수를 조정할 수 있다.
head filename.txt
-n: 출력할 줄 수를 지정한다.
head -n 5 filename.txt
filename.txt의 처음 5줄을 출력한다.
tail
tail은 기본적으로 파일의 마지막 몇 줄을 출력하는 명령어이다. 기본값으로 마지막 10줄을 출력하지만, 옵션을 사용하여 출력할 줄 수를 변경할 수 있다.
tail filename.txt
-n: 출력할 줄 수를 지정한다.
tail -n 15 filename.txt
filename.txt의 마지막 15줄을 출력한다.
-f: 실시간으로 파일의 추가되는 내용을 출력한다. 로그 파일 모니터링에 주로 사용된다.
tail -f logfile.txt
logfile.txt의 내용을 실시간으로 모니터링하며, 새로운 내용이 추가될 때마다 업데이트되어 출력된다.
검색 및 탐색
grep
grep 명령어는 주어진 패턴을 파일이나 표준 입력에서 검색하고, 일치하는 줄을 출력하는 강력한 텍스트 검색 도구이다. 주로 특정 텍스트 패턴을 찾아내거나 필터링할 때 사용된다.
grep "pattern" filename
filename에서 pattern이 포함된 줄을 출력한다.
-i (대소문자 구분 없이 검색)
grep -i "pattern" filename
-r (재귀적으로 디렉토리 검색)
grep -r "pattern" /path/to/directory
-n (줄 번호 함께 출력)
grep -n "pattern" filename
-v (일치하지 않는 줄 출력)
grep -v "pattern" filename
-c (일치하는 줄 수 출력)
grep -c "pattern" filename
grep 명령어는 파이프(|)와 결합하여 다른 명령어의 출력을 필터링할 때 매우 유용하다. 파이프는 한 명령어의 출력을 다른 명령어의 입력으로 전달하는 기능을 제공한다.
명령어 출력에서 특정 패턴 찾기
ls -l | grep "txt"
로그 파일에서 특정 키워드 찾기
cat /var/log/syslog | grep "error"
디렉토리 내 파일명 필터링
find /path/to/dir -type f | grep "log"
find
find 명령어는 리눅스와 유닉스 계열 시스템에서 파일과 디렉토리를 검색하는 데 사용되는 강력한 도구이다. 다양한 옵션과 조건을 이용해 원하는 파일이나 디렉토리를 효율적으로 찾을 수 있다.
특정 경로에서 파일 찾기
find /path/to/search -name "filename"
지정된 경로에서 filename이라는 이름의 파일을 찾는다. 이름은 대소문자를 구분한다.
대소문자를 구분하지 않고 파일 찾기
find /path/to/search -iname "filename"
-iname 옵션은 대소문자를 구분하지 않고 파일을 찾는다.
특정 확장자의 파일 찾기
find /path/to/search -name "*.txt"
특정 크기 이상의 파일 찾기
find /path/to/search -size +100M
100MB보다 큰 파일을 찾는다. 크기는 M(메가바이트), K(킬로바이트), G(기가바이트) 등의 단위로 지정할 수 있다.
파일 삭제
find /path/to/search -name "*.tmp" -type f -delete
.tmp 파일을 찾고 삭제한다. 이 명령어는 주의해서 사용해야 한다.
파이프와 결합
find . | grep "conf"
현재 디렉토리(.)와 모든 하위 디렉토리에서 conf라는 문자열이 포함된 파일 또는 디렉토리를 찾는다.
find 명령어는 논리 연산자(-and, -or, !)를 사용하여 검색 조건을 조합할 수 있다.