[C] 리눅스 TOP 명령어를 파싱하기

리눅스에서 C 프로그래밍을 하다 보면 가끔 시스템정보를 알아야 할 때가 있습니다.
메모리, 사용메모리, 프로세서 사용률 등의 정보입니다. 그때 편하게 개발 가능한 방법은 TOP 명령어를 파싱하는 방법입니다.

우선 TOP 명령어에 대해서 간단히 설명 드리겠습니다.

TOP 명령

top 명령은 활성 Linux 프로세스를 표시하는 데 사용되고 실행 중인 시스템의 동적 실시간 보기를 제공합니다.
또한 시스템의 요약 정보와 현재 Linux 커널에서 관리하는 프로세스 또는 스레드 목록을 표시합니다.

리눅스 명령창에 “top” 을 타이핑 해 보겠습니다.

[C] 리눅스 TOP 명령어를 파싱하기

출력형식의 상위 부분은 프로세스 및 리소스 사용량 통계가 포함된 대화형 명령 모드 창이 열립니다.
아래쪽은 현재 실행 중인 프로세스 목록이 포함되어 있습니다.

상당 표시항목

라인 1 현재시간과 부팅후 흐른시간, users(), load average(각각 1, 5, 15 분 동안의 평균 시스템 부하량 평균값)
Tasks 총 쓰레드 표시 running, sleeping, stopped, zombie 로 분류됨.
%Cpu(s) 새로 고침 이후 간격을 기준으로 한 CPU 상태율을 표시함.
  us, user – un-niced 사용자 프로세스를 실행하는 시간
sy, system – 커널 프로세스 실행 시간
ni, nice – niced 사용자 프로세스 실행 시간
id, idle – 커널 idle 핸들러에서 보낸 시간
wa, IO-wait – I/O 완료를 기다리는 시간
hi – 하드웨어 인터럽트 서비스에 소요 된 시간
si – 소프트웨어 인터럽트 서비스에 소요 된 시간
st – Hypervisor VM 에 할당된 시간
KiB Mem 물리적 메모리를 반영함 분류는 total, free, used, buff/cache 로 구분됨.
Kib Swap 가상 메모리를 반영함 분류는 total, free, used, avail Mem

 

하단 표시 항목

PID 작업의 고유한 프로세스 ID를 표시합니다.
USER 작업 소유자의 사용자 이름입니다.
PR 작업의 우선 순위를 나타냅니다.
NI 작업의 좋은 가치를 나타냅니다. 음의 좋은 값은 높은 우선 순위를 의미하고, 좋은 값이 양이면 우선 순위가 낮다는 것을 의미합니다.
VIRT 태스크에서 사용하는 총 가상 메모리입니다.
RES 프로세스에서 사용하는 실제 실제 메모리의 양을 나타냅니다.
SHR 작업에서 사용하는 공유 메모리 크기(kb)를 나타냅니다.
S 프로세스의 상태입니다.
%CPU CPU 사용량을 나타냅니다.
%MEM 작업의 메모리 사용량을 표시합니다.
TIME+ CPU 시간, ‘TIME’과 동일하지만 100분의 1초를 통해 더 많은 세분성을 반영합니다.
COMMAND 실행 중인 명령입니다.

top 실행 옵션

  • -b : 배치모드 옵션
  • -n : top 실행 주기를 설정
  • -p : process ID

top 명령으로 출력문 가져오기

top 을 실행하면 입력문처럼 항상 떠 있는 것을 볼 수 있습니다.
‘q’ 또는 Ctrl+C 를 타이핑 해야만 탈출 할 수 있습니다.

출력문을 파싱하기 위해서는 한번 실행후 그 값을 문자열로 받아와야겠지요.

한번 실행 하고 자동종료 되게끔 해보겠습니다.

top -n1

을 타이핑하면 화면에서 한번 출력되고 종료가 됩니다.

출력문을 문자열로 받아오는 방법은 이전에 소개 드렸습니다.

[C] Linux 의 쉘명령 출력을 변수로 받기 (harostudio.co.kr)

출력 파싱하기

이렇게 정형화된 문자열을 파싱하는 좋은 방법으로는 sscanf 라는 함수가 존재합니다.
정형화된 문자열을 파싱하기에 더할 나위 없이 좋은 함수 입니다.

man page 에서 sscanf 에 대해 잠시 살펴 보겠습니다.

sscanf()

sscanf() 함수는 buffer에서 argument-list가 제공하는 위치로 데이터를 읽습니다.
각 argument는 format-string에 서 유형 지정자에 대응하는 유형의 변수에 대한 포인터여야 합니다.

리턴값

sscanf() 함수는 성공적으로 변환 및 지정된 필드 수를 리턴합니다. 리턴값은 읽었지만 지정되지 않은 필드는 포함하지 않습니다.
리턴값은 변환 전에 스트링 끝이 나타난 경우 EOF입니다.

format

%[*][폭(width)][한정자(modifiers)]타입(type)

종류설명
* 데이터를 stdin 에서 받아들이지만 무시된다. 물론, 이에 대응되는 인자에는 받아들인 데이터가 저장되지 않고 이 인자는 다음 형식 태그에 대응된다.
예를 들어 scanf("%*d%d", i,j); 의 경우 먼저 수를 입력하더라도 %*d 형식이므로 무시 된다. 그 다음 수를 입력하면 %d 형식 태그가 j 가 아닌 i 에 대응되어 i 에 그 다음 입력한 수가 들어가게 된다. 이 때 j 에는 아무런 값도 들어가지 않는다.
stdin 에서 읽어들일 최대 문자 수를 지정한다. 예를 들어 scanf("%10s", str); 로 했을 경우 stdin 에서 최대 10 문자를 읽어와 str 에 저장한다. 이 때 주의할 점은 str 에는 NULL 문자가 들어갈 수 있는 충분한 공간이 남아 있어야 한다.
한정자 입력받는 데이터의 크기를 지정한다. int, unsigned int, float 형에 대해 입력받는 데이터의 크기를 설정할 수 있다. h 의 경우 short int (d, i, n 의 경우) 혹은 unsigned short int (o, u, x 일 경우). l 의 경우 long int (d, i, n 의 경우) 혹은 unsigned long int (o, u, x 일 경우), 혹은 double (e, f, g 일 경우). 마지막으로 L 의 경우 long double (e, f, g 일 경우) 에 사용할 수 있다.
타입데이터를 어떠한 형식으로 혹은 어떠한 값만을 읽어들어야 할 지에 대해 지정해준다. 아래 표를 참고.
타입대응되는 입력 방식대응되는 인자의 형태
d 십진법으로 표현된 정수: 말그대로 십진법으로 쓰인 정수로, + 나 - 기호로 시작할 수도 있다.int *
e, E, f, g, G 부동 소수점: 소수점을 포함하고 있는 소수(decimal number) 로 + 나 - 기호로 시작할 수도 있으며, e 나 E 문자(10 의 지수를 나타내기 위해)를 포함할 수 도 있다. -732.103, 12e-4, +123.10 은 모두 올바른 입력이다.float *
o8진법으로 표현된 정수int *
s문자열: 공백문자를 찾을 때 까지 문자들을 읽어들인다.char *
u부호가 없는 십진법으로 표현된 정수unsigned int *
x, X16진법으로 표현된 정수int *

예제 코드

예제로 시스템의 물리적 메모리의 전체, 여유공간, 사용 공간을 출력하는 프로그램을 보여드리겠습니다.

#include <stdio.h>

int run_shell_command(char *command, char *output, int *out_len)
{
    int result;
    if (!command) return -1;

    result = -1;

    if (output)
    {
        FILE* file;
        file = popen(command, "r");

        if (file)
        {
            *out_len = fread(output, 1, *out_len - 1, file);
            if (*out_len >= 0)
                output[*out_len] = 0;
            else
                output[0] = 0;
            result = pclose(file);
        }
    }
    else
    {
        result = System(command);
    }

    return result;

}

int main()
{
    char output[512];
    int length = 512;

	int total, free, used;
	
	run_shell_command("top -n1 | grep \"KiB Mem\"", output, &length);

    int chk = sscanf(output, "KiB Mem %*s %d %*s %d %*s %d", &total, &free, &used);          

	printf("total memory : %d  \nfree memory : %d\nused memory %d\n", total, free, used);
}

위와 같이 코딩하고 출력내용을 샆펴 보겠습니다.

[C] 리눅스 TOP 명령어를 파싱하기

아주 간단하고 쉽게 top 명령어중 필요한 값을 파싱해서 출력하는 프로그램을 만들어 보았습니다.

Leave a Comment