프로세스는 실행 중인 프로그램의 인스턴스이다. 운영 체제가 프로그램의 코드와 데이터를 메모리에 로드하고 실행할 때, 프로세스가 생성된다. 프로세스는 운영 체제의 리소스(메모리, CPU 시간, 파일 핸들 등)를 할당받으며, 이러한 리소스를 사용하여 작업을 수행한다.
프로세스 ID (PID): 각 프로세스는 고유한 식별 번호인 PID를 가진다. 이를 통해 시스템 내에서 프로세스를 구분하고 관리할 수 있다.
메모리 공간: 프로세스는 코드(프로그램 자체), 데이터(변수, 동적 할당 메모리 등), 스택(함수 호출과 로컬 변수) 등을 포함한 독립된 메모리 공간을 가진다.
실행 상태: 프로세스는 생성, 준비, 실행, 대기, 종료 등의 여러 상태를 거치며, 스케줄러에 의해 관리된다.
컨텍스트: 프로세스의 컨텍스트는 CPU 레지스터 상태, 프로그램 카운터, 스택 포인터 등 실행에 필요한 정보를 포함한다.
이 두 함수는 프로세스의 생성과 실행을 다루는 기본적인 시스템 호출이다.
기능: fork() 시스템 호출은 호출하는 현재 프로세스(부모 프로세스)의 복사본을 생성하는 데 사용된다. 이 복사본을 자식 프로세스라고 한다.
동작 방식: 자식 프로세스는 부모 프로세스의 메모리 이미지, 오픈된 파일 디스크립터, 환경 설정 등을 복사한다. 하지만, 부모 프로세스와 자식 프로세스는 서로 다른 메모리 공간을 가지므로, 이후에는 독립적으로 실행된다.
반환 값: fork()는 부모 프로세스에게는 자식 프로세스의 PID(Process ID)를, 자식 프로세스에게는 0을 반환합니다. 실패한 경우에는 -1을 반환하고, 오류 원인을 나타내는 값을 errno에 설정한다.
기능: exec() 시스템 호출은 현재 프로세스의 메모리 이미지를 새로운 프로그램의 메모리 이미지로 대체하는 데 사용된다. 즉, 현재 실행 중인 프로그램을 종료하고 새로운 프로그램을 실행한다.
동작 방식:exec()는 새로운 프로그램의 실행 파일 경로, 명령줄 인자, 환경 변수를 인자로 받는다. 실행에 성공하면 현재 프로세스는 새로운 프로그램으로 완전히 대체되며, 이전 프로그램의 실행은 종료된다.
반환 값: 성공적으로 실행될 경우, exec()는 반환하지 않는다. 즉, 이 함수 이후의 코드는 새로운 프로그램에서 계속 실행된다. 실패할 경우에만 -1을 반환하고, errno에 오류 원인을 설정한다.
fork()와 execve()는 종종 함께 사용되어, 새로운 프로그램을 실행하는 독립적인 프로세스를 생성하는 패턴에 사용된다.
부모 프로세스가 fork()를 호출하여 자식 프로세스를 생성한다.
자식 프로세스에서 exec()를 호출하여 새로운 프로그램으로 자신을 대체한다.
부모 프로세스는 자식 프로세스의 실행을 기다리거나, 다른 작업을 계속 진행할 수 있다.
이 방법을 통해, 리눅스 시스템은 새로운 프로그램을 실행할 때 기존 프로세스의 환경을 유지하면서도, 새로운 프로그램을 독립적인 실행 단위로 관리할 수 있다.
ps ax
명령어를 입력한다면?터미널에서 ps ax 명령어를 실행할 때, fork() 함수는 현재의 프로세스를 복제하여 자식 프로세스를 생성하고, exec() 함수는 이 자식 프로세스에서 ps 프로그램을 로드하여 실행한다. 이 과정을 통해 터미널은 명령어 실행 동안 사용자와의 상호작용을 계속 유지할 수 있으며, ps ax 명령어의 실행 결과는 터미널에 출력된다.
표준 입력 (Standard Input, STDIN)
식별 번호: 0
표준 입력은 프로그램에 데이터를 입력하기 위한 기본 스트림이다. 사용자로부터 입력을 받거나, 다른 프로그램의 출력을 입력으로 사용할 수 있다.
예시: 키보드 입력을 받거나, 파이프(|)를 사용하여 다른 프로그램의 출력을 입력으로 받는다.
표준 출력 (Standard Output, STDOUT)
식별 번호: 1
표준 출력은 프로그램의 결과나 데이터를 출력하기 위한 기본 스트림이다. 기본적으로 터미널 또는 콘솔 화면에 데이터를 출력하지만, 파일로 리디렉션하거나 다른 프로그램의 입력으로 전달할 수도 있다.
예시: 프로그램 실행 결과를 화면에 출력하거나, > 연산자를 사용하여 파일에 출력 결과를 저장한다.
표준 에러 (Standard Error, STDERR)
식별 번호: 2
표준 에러는 프로그램 실행 중 발생하는 에러 메시지를 출력하기 위한 스트림이다. 표준 에러는 표준 출력과 별개로 관리되므로, 프로그램의 정상적인 출력과 에러 메시지를 분리하여 처리할 수 있다.
예시: 에러 메시지를 화면에 출력하거나, 2> 연산자를 사용하여 에러 메시지만 별도의 파일에 저장한다.
파이프는 두 프로그램 간의 데이터 흐름을 연결하는 강력한 메커니즘이다. 파이프를 사용하면 한 프로그램의 출력을 다른 프로그램의 입력으로 직접 전달할 수 있으며, 이를 통해 복잡한 작업을 단순하고 효율적으로 처리할 수 있다. 파이프라인은 주로 쉘에서
|
기호를 사용하여 구성된다.
출력과 입력 연결: 파이프라인은 첫 번째 명령어의 표준 출력(STDOUT)을 두 번째 명령어의 표준 입력(STDIN)에 연결한다. 이 과정은 여러 명령어를 연결하여 확장할 수 있으며, 각 명령어의 출력은 다음 명령어의 입력이 된다.
프로세스 생성: 쉘은 파이프라인의 각 명령어에 대해 별도의 프로세스를 생성한다. 이 프로세스들은 동시에 실행될 수 있으며, 데이터는 파이프를 통해 실시간으로 전달된다.
데이터 처리: 각 명령어는 파이프를 통해 받은 데이터를 처리하고 결과를 다음 파이프(또는 최종 목적지)로 전송한다. 이 과정은 파이프라인의 마지막 명령어까지 반복된다.
유연성: 파이프라인을 사용하면 간단한 명령어를 조합하여 복잡한 작업을 수행할 수 있다. 각 명령어는 독립적으로 동작하므로, 다양한 기능을 가진 도구들을 유연하게 결합할 수 있다.
효율성: 데이터는 필요한 처리 단계를 거치면서 바로 다음 단계로 전달된다. 이는 중간 단계에서 데이터를 저장하고 다시 읽어야 하는 오버헤드를 줄여준다.
동시 실행: 파이프라인의 명령어들은 각각 별도의 프로세스로 실행되기 때문에, 멀티코어 프로세서의 이점을 활용하여 명령어를 동시에 실행할 수 있다. 이는 전체 파이프라인의 실행 속도를 향상시킨다.
ls | sort -r
ls 명령어 실행
ls 명령어는 현재 디렉토리의 파일 목록을 표준 출력으로 나열한다.
이 명령어는 파일과 디렉토리의 이름을 나열하며, 기본적으로 알파벳 순으로 정렬된 상태로 출력된다.
파이프(|)를 통한 데이터 전달
| 기호는 ls의 표준 출력을 sort 명령어의 표준 입력으로 전달한다.
파이프는 ls 명령어의 출력 데이터를 sort 명령어로 실시간으로 전송한다.
sort -r 명령어 실행
sort 명령어는 입력된 데이터를 정렬한다. 여기서 -r 옵션은 결과를 역순(내림차순)으로 정렬하라는 의미다.
sort는 파이프를 통해 전달받은 데이터(즉, ls의 출력)를 내림차순으로 정렬한다.
정렬된 데이터 출력
sort -r의 출력은 터미널에 나타난다. 이 출력은 현재 디렉토리의 파일 및 디렉토리 목록을 역순으로 정렬한 결과다.
cd /bin | ls | sort -r
위 명령어를 치면 /bin 폴더의 파일 목록을 역순해서 출력할 거 같지만 그렇지 않다.
파이프의 각 명령은 별도의 자식 프로세스에서 실행된다. 즉, cd /bin, ls, sort 각각이 자신만의 프로세스에서 실행되며, 이들 프로세스는 서로 독립적이다.
cd /bin이 파이프의 일부로 실행되면, 이 명령어는 오직 그 명령어를 실행하는 자식 프로세스의 작업 디렉토리만 변경한다. 부모 프로세스인 원래 셸의 작업 디렉토리는 변경되지 않는다.
파이프를 통해 실행되는 cd 명령은 해당 명령이 실행된 자식 프로세스의 컨텍스트 내에서만 유효하다.
쉘 내장 명령어(shell built-in commands)는 쉘 자체에 의해 직접 실행되는 명령어로, 별도의 실행 파일 없이 쉘 프로세스 내에서 처리된다. 이러한 명령어들은 쉘의 작업 환경을 설정하거나, 쉘 세션을 제어하는 데 사용된다.
/bin
/bin 디렉토리에는 사용자가 기본적으로 사용하는 필수 명령어들이 포함되어 있다. 예를 들어, ls, cp, mv, cat
등과 같은 명령어들이 여기에 속한다.
이 명령어들은 시스템 부팅과 복구에 필요하며, 단일 사용자 모드에서도 사용 가능해야 하는 명령어들입니다.
/usr/bin
/usr/bin 디렉토리는 사용자가 사용할 수 있는 애플리케이션 프로그램과 명령어들을 포함하고 있다. 여기에는 시스템의 기본 도구 외에도 다양한 추가 프로그램이 포함된다.
대부분의 사용자 수준의 애플리케이션과 프로그램이 여기에 설치된다.
/sbin
/sbin 디렉토리에는 시스템 관리 및 관리 명령어들이 포함되어 있다. 이 명령어들은 주로 시스템 관리자(root)에 의해 사용된다.
예를 들어, reboot, fdisk, ifconfig 등의 명령어가 이 디렉토리에 위치한다.
/usr/sbin
/usr/sbin 디렉토리는 /sbin과 유사하지만, 일반적으로 덜 중요한 시스템 관리 명령어를 포함한다. 주로 네트워킹, 시스템 관리, 서버 프로세스와 관련된 명령어들이 여기에 설치된다.
/usr/local/bin (/opt/homebrew/bin)
/usr/local/bin 디렉토리는 시스템 표준 패키지 관리자에 의해 관리되지 않는 사용자 또는 관리자가 직접 컴파일하거나 설치한 프로그램을 위한 곳이다. 이곳에 설치된 프로그램들은 시스템 전체에 걸쳐 사용할 수 있다.