NGMsoftware

NGMsoftware
로그인 회원가입
  • 매뉴얼
  • 학습
  • 매뉴얼

    학습


    기타 2부 - 유용한 리눅스 명령어 모음. (A collection of useful Linux commands.)

    페이지 정보

    본문

    안녕하세요. 엔지엠소프트웨어입니다. 1부에 이어 초급 또는 중급 서버 개발자가 알아야할 리눅스 명령어들에 대해 알아보도록 하겠습니다. 1부에서 폴더 또는 파일의 권한에 대해 알아볼 때 링크를 잠깐 언급했었습니다. 권한에서 파일은 -, 디렉토리는 d, 링크는 l로 시작한다고 했었는데 기억 나시죠^^ 링크에 대해 알아보기전에 리눅스의 파일 시스템에 대한 이해가 필요합니다. 링크는 Hard Link와 Soft Link로 나뉩니다. Soft Link는 심볼릭 링크(Symbolic Link)라고 부릅니다. 아래 표는 링크 파일과 운영 체제의 파일 시스템을 간단하게 표시하고 있습니다.

    ※ inode는 구조체로 크게 두부분으로 나뉩니다. 파일 정보를 저장하는 부분과 실제 파일의 내용이 저장되는 데이타 블록의 주소입니다. 데이타 블록은 직접 블록, 간접 블록과 이중 간접 블록으로 구분됩니다. 1부에서 알아본 ls 명령은 inode에 저장된 파일 정보를 읽어서 출력합니다.

    YA8oLH3.png

     

     

     

    위 표에서 좌측 Link file은 사람이 인식하기 쉬운 방식입니다. 하지만, 운영체제 입장에서 이 방식은 그리 좋지 않습니다. 그래서 별도의 우측과 같은 File system을 사용하고 있습니다. 이 둘을 연결할 수 있는 정보가 inode에 담겨 있습니다. inode는 Link file과 File system이 1:1로 매핑되고, 파일이 생성될 때 고유한 값으로 생성됩니다. 하드 링크는 파일에만 설정할 수 있습니다.  Ref(Reference, 참조)는 링크 파일의 갯수를 나타냅니다. Link는 위 표에서 inode값이 3인 내용을 참조해야 합니다. 엔지엠 에디터를 실행하는 ngm_editor.sh 파일을 원본으로 생성하고, 이를 복사하여 ngm_player.sh을 만들었습니다. 이 때 원본과 복사본은 같은 inode 값을 가지지만, 우측 File system의 Ref는 2가 되는걸 알 수 있습니다. 우리가 항상 파일을 만들거나 수정 또는 삭제할 때 이 동작들이 수행됩니다. 파일을 생성하면 새로운 inode가 만들어지고 Ref는 무조건 1입니다. 복사하면 Ref가 2가 됩니다. 수정하면 동시에 수정되지만, 삭제는 개별적으로 동작합니다. File system에서 파일을 삭제한다는 것은 Ref가 0이 된다는 뜻이므로 inode 3의 Ref는 2이기 때문에 ngm_player.sh를 삭제하더라도 링크만 삭제될뿐 파일은 사라지지 않습니다.

     

    심볼링 링크는 윈도우의 바로가기 만들기를 생각하면 이해하기 쉽습니다.

    3IQLgYf.png

     

     

    리눅스의 심볼릭 링크도 윈도우의 바로 가기와 동일합니다. 심볼릭 링크는 하드 링크처럼 물리적인 하드 디스크의 파일을 가리키는게 아닌 링크 파일을 참조합니다. 다시 말해서 하드 링크는 파일 시스템을 참조하고 심볼릭 링크는 링크 파일이 링크 파일을 참조하는 형식입니다. 그래서 파일이든 폴더든 구분없이 참조가 가능합니다. 오픈 소스를 배포할 때 대부분은 library1.so, library2.so와 같이 릴리즈되는 버전을 뒤에 붙여서 배포합니다. 잘 생각해보면 이렇게 배포된 라이브러리를 참조하는 서비스들은 매번 라이브러리 이름을 바꿔주거나 참조를 변경해야 하는 번거로움이 발생합니다. 그래서 library.so 심볼릭 링크를 만들어서 배포하고, 배포하기 전 심볼릭 링크를 library2.so로 변경합니다. 그러면, 이 라이브러리를 사용하여 서비스를 개발하는 개발자들은 더이상 신경쓸일이 없으므로, 오픈 소스를 가져다가 사용하기가 매우 편리해집니다. 이제 하드 링크와 심볼릭 링크를 만들어 볼까요?

     

    1. ln (link)

    ln 명령으로 심볼릭 링크를 만드는 방법입니다. ln -s source target와 같이 만듭니다. 아래와 같이 ngm_editor의 심볼릭 링크인 editor를 만들었습니다. 권한쪽을 보면 앞에 l이 붙어 있는것을 확인할 수 있고, 심볼릭 링크가 어디를 가리키고 있는지도 확인할 수 있습니다.

    [admin@a6cb3ce57d23 ~]$ ln -s ngm_editor editor
    [admin@a6cb3ce57d23 ~]$ ls -l
    total 24
    -rw-r--r-- 1 admin ngmsoftware 8440 Aug 21 08:45 a.out
    lrwxrwxrwx 1 admin ngmsoftware   10 Aug 22 00:33 editor -> ngm_editor
    -rw-r--r-- 1 admin ngmsoftware    0 Aug 21 06:51 editor.exe
    -rw-r--r-- 1 admin ngmsoftware   71 Aug 21 08:42 ngm.c
    drwxr-xr-x 2 admin ngmsoftware 4096 Aug 21 10:52 ngm_editor
    drwxr-xr-x 3 admin ngmsoftware 4096 Aug 21 10:45 NGM_Player
    -rw-r--r-- 1 admin ngmsoftware    0 Aug 21 06:51 player.exe
    [admin@a6cb3ce57d23 ~]$

     

    심볼릭 링크를 삭제하고, 플레이어를 에디터로 다시 만듭니다. 이 시나리오는 위에서 설명한것과 같이 새 버전의 라이브러리를 릴리즈할 때 심볼릭 링크를 변경하는 방법입니다.

    [admin@a6cb3ce57d23 ~]$ rm -f editor
    [admin@a6cb3ce57d23 ~]$ ln -s NGM_Player editor
    [admin@a6cb3ce57d23 ~]$ ls -l
    total 24
    -rw-r--r-- 1 admin ngmsoftware 8440 Aug 21 08:45 a.out
    lrwxrwxrwx 1 admin ngmsoftware   10 Aug 22 00:37 editor -> NGM_Player
    -rw-r--r-- 1 admin ngmsoftware    0 Aug 21 06:51 editor.exe
    -rw-r--r-- 1 admin ngmsoftware   71 Aug 21 08:42 ngm.c
    drwxr-xr-x 2 admin ngmsoftware 4096 Aug 22 00:37 ngm_editor
    drwxr-xr-x 3 admin ngmsoftware 4096 Aug 21 10:45 NGM_Player
    -rw-r--r-- 1 admin ngmsoftware    0 Aug 21 06:51 player.exe
    [admin@a6cb3ce57d23 ~]$

     

    만약, editor 심볼릭 링크가 참조하는 NGM_Player 원본 파일이 삭제되면 어떻게 될까요? editor는 원본 파일을 찾을 수 없으므로 아무런 역할도 없는 쓰레기 파일이 됩니다. 윈도우의 경우에도 바로 가기 파일이 참조하는 원본 파일이 사라지면 동일하게 아무런 역할도 할 수 없습니다. 다만, 바로 가기를 실행하면 원본 파일을 찾을 수 없기 때문에 바로 가기를 삭제하겠다고 물어보기는 합니다. 이번에는 하드 링크를 만들어보겠습니다. 아래와 같이 심볼릭 링크와 동일하지만, -f 옵션을 사용하지 않으면 하드 링크가 만들어집니다. 하드 링크는 ls -li로 확인할 수 있습니다.

    [admin@a6cb3ce57d23 ~]$ ln a.out my_program
    [admin@a6cb3ce57d23 ~]$ ls -li
    total 36
    22200 -rw-r--r-- 2 admin ngmsoftware 8440 Aug 21 08:45 a.out
    19758 lrwxrwxrwx 1 admin ngmsoftware   10 Aug 22 00:37 editor -> NGM_Player
     8679 -rw-r--r-- 1 admin ngmsoftware    0 Aug 21 06:51 editor.exe
    22200 -rw-r--r-- 2 admin ngmsoftware 8440 Aug 21 08:45 my_program
    19730 -rw-r--r-- 1 admin ngmsoftware   71 Aug 21 08:42 ngm.c
    19745 drwxr-xr-x 2 admin ngmsoftware 4096 Aug 22 00:37 ngm_editor
     8678 drwxr-xr-x 3 admin ngmsoftware 4096 Aug 21 10:45 NGM_Player
     8680 -rw-r--r-- 1 admin ngmsoftware    0 Aug 21 06:51 player.exe
    [admin@a6cb3ce57d23 ~]$

     

    a.out 파일을 하드 링크로 만든 my_program의 inode 값이 22200으로 같다는걸 알 수 있습니다. a.out와 my_program은 하드 링크이고, a.out 파일을 수정하면 my_program도 같이 수정됩니다. a.out 파일이 원본이기는 하지만, 하드 링크로 my_program을 만들면 원본과 복사본의 개념이 사라집니다. 위의 표에서 inode와 Ref로는 원본과 복사본을 구분하지 않기 때문입니다. 여기서 a.out 원본 파일을 삭제하더라도 my_program에는 영향이 없습니다. 위에서도 설명했듯이 Ref가 2에서 1로 변경될 뿐 파일이 물리적으로 삭제된건 아니기 때문입니다.

    CL5aRt6.png

     

     

    2. man (manual)

    운영체제나 시스템에 대한 배경 지식이 많이 필요없는 명령어들만 남았습니다. 우리가 가장 먼저 알아야 하는 명령어는 man입니다. 이름에서 알 수 있듯이 리눅스에서 제공하는 명령어들의 매뉴얼을 볼 수 있는 명령입니다. 다음에 알아볼 cat에 대한 내용을 출력 해볼까요? man 명령은 리눅스에서 제공하는 명령에 대해 도움말을 확인할 수 있습니다. 명령은 데비앙이나 우분투, 센트오에스등등... 차이가 있을수는 있습니다.

    [admin@4c463032a990 ~]$ man cat
    NAME         top
           cat - concatenate files and print on the standard output
    SYNOPSIS         top
           cat [OPTION]... [FILE]...
    DESCRIPTION         top
           Concatenate FILE(s) to standard output.
    
           With no FILE, or when FILE is -, read standard input.
    
           -A, --show-all
                  equivalent to -vET
    
           -b, --number-nonblank
                  number nonempty output lines, overrides -n
    
           -e     equivalent to -vE
    
           -E, --show-ends
                  display $ at end of each line
    
           -n, --number
                  number all output lines
    
           -s, --squeeze-blank
                  suppress repeated empty output lines
    
           -t     equivalent to -vT
    
           -T, --show-tabs
                  display TAB characters as ^I
    
           -u     (ignored)
    
           -v, --show-nonprinting
                  use ^ and M- notation, except for LFD and TAB
    
           --help display this help and exit
    
           --version
                  output version information and exit

     

    3. cat (concatenate)

    cat(캣)은 리눅스와 유닉스에 입문할 때 우선적으로 배우는 가장 기본이 되는 명령중에 하나입니다. 그만큼 많이 사용된다는 의미입니다. cat은 파일 내용을 출력할 때 사용합니다. 아래와 같이 SSD와 하드디스크의 시리얼 넘버를 스푸핑하는 소스를 볼 수 있습니다.

    qIsMXmo.png

     

     

    소스 내용이 한 화면에 모두 표시되지 않는 경우 파이프(|, 역슬래시 위에 있는 기호로 버티칼바 또는 파이프)로 cat 명령에 more 명령을 전달할 수 있습니다. 파이프는 조건에서 또는 이라는 의미도 가지고 있습니다. 언어 관점에서는 두개를 사용하고, 한개는 비트 연산입니다. 아무튼, 파이프를 사용해서 more를 전달하면 아래와 같이 화면 마지막에 more가 표시됩니다. 스페이스바를 누르면 다음 화면으로 넘어갑니다. 한줄씩 보려면 엔터를 누르면 됩니다. 종료하려면 q를 누르세요.

    [admin@4c463032a990 source]$ cat hwid_spoofer.c | more
    nclude "stdafx.h"
    
    struct {
            DWORD Length;
            NIC_DRIVER Drivers[0xFF];
    } NICs = { 0 };
    
    PDRIVER_DISPATCH DiskControlOriginal = 0, MountControlOriginal = 0, PartControlOriginal = 0, NsiControlOriginal = 0, Gpu
    ControlOriginal = 0;
    
    /**** DISKS ****/
    NTSTATUS PartInfoIoc(PDEVICE_OBJECT device, PIRP irp, PVOID context) {
            if (context) {
                    IOC_REQUEST request = *(PIOC_REQUEST)context;
                    ExFreePool(context);
    
                    if (request.BufferLength >= sizeof(PARTITION_INFORMATION_EX)) {
                            PPARTITION_INFORMATION_EX info = (PPARTITION_INFORMATION_EX)request.Buffer;
                            if (PARTITION_STYLE_GPT == info->PartitionStyle) {
                                    memset(&info->Gpt.PartitionId, 0, sizeof(GUID));
                            }
                    }
    
                    if (request.OldRoutine && irp->StackCount > 1) {
                            return request.OldRoutine(device, irp, request.OldContext);
                    }
            }
    
            return STATUS_SUCCESS;
    --More--

     

    위에서 "cat 파일명"을 사용했습니다. 모니터로 출력해서 내용을 확인 했죠? 출력을 모니터가 아닌 파일로 하면 파일 복사와 동일한 결과를 나타냅니다. 여기서 조심해야 할 부분은 오타로 인해 기존 파일명과 동일하게 입력하면 다시 말해서 dummy.c 파일이 존재한다면 덮어쓰기가 수행됩니다. 의도하지 않은 실수로 인해 파일에 문제가 발생할 수 있습니다. 그래서, cat hwid_spoofer.c >> dummy.c 와 같이 꺽쇠 2개를 사용하면 dummy.c 파일이 존재하는 경우 마지막에 붙여 넣기하게 됩니다.

    [admin@4c463032a990 source]$ cat hwid_spoofer.c > dummy.c
    [admin@4c463032a990 source]$ cat dummy.c
    ...
    NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING registry_path) {
            UNREFERENCED_PARAMETER(registry_path);
            driver->DriverUnload = DriverUnload;
    
            ULONG64 time = 0;
            KeQuerySystemTime(&time);
            SEED = (DWORD)time;
    
            CHAR alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
            for (DWORD i = 0, l = (DWORD)strlen(SERIAL); i < l; ++i) {
                    SERIAL[i] = alphabet[RtlRandomEx(&SEED) % (sizeof(alphabet) - 1)];
            }
    
            printf("++ loading (serial: %s)\n", SERIAL);
    
            SpoofDisks();
            SpoofVolumes();
            SpoofNIC();
            SpoofSMBIOS();
            SpoofGPU();
    
            printf("++ loaded\n");
    
            return STATUS_SUCCESS;
    }
    [admin@4c463032a990 source]$

     

    요즘은~ 윈도우에서 직접 개발하고 FTP나 CI/CD와 같은 시스템에서 배포하게 됩니다. 그래서, 간단한 콘피그 정도만 서버에서 수정합니다. 이때에도 vi를 사용해서 몇몇 옵션만 바꿔주면 되기 때문에 문제될 일은 없지만~ 그래도 기본적인건 알아두는게 좋습니다. 규모가 있는 프로젝트라면 이런 실수를 방지하기 위한 여러가지 시스템들이 존재합니다.

     

    4. head

    cat을 사용해도 되지만, head를 사용하면 파일의 앞에서 몇 라인만 출력할 수 있습니다. 아무런 옵션이 없으면 10라인을 출력해줍니다.

    [admin@4c463032a990 source]$ head dummy.c
    nclude "stdafx.h"
    
    struct {
            DWORD Length;
            NIC_DRIVER Drivers[0xFF];
    } NICs = { 0 };
    
    PDRIVER_DISPATCH DiskControlOriginal = 0, MountControlOriginal = 0, PartControlOriginal = 0, NsiControlOriginal = 0, GpuControlOriginal = 0;
    
    /**** DISKS ****/
    [admin@4c463032a990 source]$

     

    라인을 좀 더 출력하고 싶으면 라인 수 또는 바이트 양으로 옵션을 선택할수도 있습니다. 라인은 -n 옵션 뒤에 라인 수를 입력하고, 바이트는 -c 옵션 뒤에 출력할 바이트를 입력해줍니다. 또한, 위에서 배운 >(꺽쇠)를 이용해서 출력을 다른 파일로 보낼수도 있습니다.

    [admin@4c463032a990 source]$ head -n 100 dummy.c
    nclude "stdafx.h"
    
    struct {
            DWORD Length;
            NIC_DRIVER Drivers[0xFF];
    } NICs = { 0 };
    
    PDRIVER_DISPATCH DiskControlOriginal = 0, MountControlOriginal = 0, PartControlOriginal = 0, NsiControlOriginal = 0, GpuControlOriginal = 0;
    ...
    
    [admin@4c463032a990 source]$

     

    5. tail

    tail(태일) 명령은 4번의 head와 반대로 파일의 끝에서부터 출력해줍니다. 자 여기서~ head와 tail중에서 어떤것을 많이 사용할까요? 당연하게도 tail을 많이 사용합니다. 저뿐만 아니라 대부분의 개발자가 그럴겁니다. 우리가 프로젝트를 진행하고, 서버에 배포하면 특정 위치에 로그를 생성하게 됩니다. 이 로그를 여러 시스템에서 활용(대표적으로 스플렁크)하겠지만, 개발자들은 배포 또는 패치 후 로그를 모니터링하게 됩니다. 이때 로그를 모니터링하기 위해 tail을 사용합니다. tail에 -f 옵션을 사용하면 마지막에 출력이 멈추고, 해당 파일에 내용이 추가되면 실시간으로 갱신됩니다.

    [admin@4c463032a990 source]$ tail -f dummy.c
            SpoofDisks();
            SpoofVolumes();
            SpoofNIC();
            SpoofSMBIOS();
            SpoofGPU();
    
            printf("++ loaded\n");
    
            return STATUS_SUCCESS;
    }
    

     

    이 테스트를 위해 터미널을 하나 더 열어줍니다. 그리고, tail로 감시하고 있는 dummy.c 파일의 마지막에 "Welcome to ngmsoftware" 문자열을 추가 해보겠습니다. 아래 동영상을 보면 좌측의 tail -f dummy.c 마지막에 자동으로 갱신되는걸 알 수 있습니다. 서버 개발 후 디버깅이나 모니터링시 많이 사용되므로 꼭 알고 넘어가면 좋겠습니다. 이외에도 위에 잠깐 언급했던 스플렁크를 통해 로그를 검사하고 이벤트를 발생시킬 수 있습니다. 스플렁크 쿼리를 배워야 하는 러닝커브가 존재하지만, 거대 시스템에서 대부분 도입하고 있으므로 어느정도 학습하면 도움이 될겁니다.

    hLEcUZX.gif

     

     

    6. grep (global / regular expression / print)

    그렙은 검색하고자 하는 문자열을 옵션으로 주면 해당 파일에서 일치하는 문자열들을 찾아주는 명령입니다. dummy.c에 앞서 추가한 ngmsoftware 문자가 있는지 검색 해보겠습니다.

    [admin@4c463032a990 source]$ echo "Welcome to ngmsoftware" >> dummy.c
    [admin@4c463032a990 source]$ grep ngmsoftware *.c
    dummy.c:Welcome to ngmsoftware
    [admin@4c463032a990 source]$

     

    테스트를 위해 아래와 같이 CHAR 를 찾아봅니다. 아래 그림과 같이 PCHAR, PWCHAR, WCHAR과 같이 CHAR가 포함된 모든 라인이 출력되는걸 알 수 있습니다.

    qzGEGcn.png

     

     

    정확하게 CHAR만 찾고 싶으면 -w 명령을 주면 됩니다. 아래와같이 원하는 결과를 얻었습니다. 파일명을 *(아스테리스크, 전부 매치되는 의미) 로 설정했기 때문에 dummy와 hwid_spoofer가 모두 찾아졌습니다. 당연한 이야기겠지만 ngmsoftware를 찾으면 dummy.c 하나만 찾아지게 됩니다.

    [admin@4c463032a990 source]$ grep -w CHAR *.c
    dummy.c:        CHAR alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    hwid_spoofer.c: CHAR alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    [admin@4c463032a990 source]$

     

    grep은 개발자가 가장 많이 사용하는 명령어입니다. 앞서 설명한 파이프와 같이 사용합니다. 실행중인 프로세스를 검색할 때도 유용합니다. 주로, 서버 개발을 자바로 하다보니 ps -ef | grep java로 실행중인 프로세스를 확인합니다. 문제가 있는 프로세스는 kill로 직접 죽이기도 합니다. 보통은 안전을 위해 stop.sh을 만들어서 사용합니다.

    [admin@4c463032a990 source]$ ps -ef | grep tail
    admin       65    30  0 02:49 pts/1    00:00:00 tail -f dummy.c
    admin      115    82  0 03:24 pts/2    00:00:00 grep --color=auto tail
    [admin@4c463032a990 source]$

     

    7. less

    less 명령은 단순하게 파일을 열어서 내용을 볼 수 있는 뷰어입니다. 보통 개발자들이 파일의 내용을 확인할 때 vi 또는 cat을 사용합니다. vi는 강력하지만 에디터이기 때문에 사이즈가 큰 파일 또는 로그와 같은 파일들을 단순히 확인하는 용도로 사용하기엔 무리가 있습니다. 타이트하게 운영되는 서버에서 1gb가 넘는 로그 파일을 vi로 열면 어떤 문제가 발생할지 예측하기가 힘듭니다. 또는 터미널과 같은 프로그램으로 원격 접속한 상태라면 메모리에 1gb를 사용하고 네트워크 트레픽도 1gb가 발생합니다. 로그를 보고 문제를 해결하려다가 더 큰 문제를 만들수도 있습니다. 그래서, less를 사용합니다. 화면에 출력되는 내용만큼만 메모리에 로드되기 때문입니다. 여기까지 less를 왜 써야 하는지에 대해 설명했지만... 그래도 사용하는 개발자는 거의 없습니다. 사이즈가 큰 로그 파일을 시스템이 아예 만들지 않기 때문입니다. log4j나 log4net과 같은 로그 매니저를 사용합니다. 대부분 10mb로 제한을 두기 때문에 이러한 문제를 사전에 예방할 수 있습니다.

     

    간단하게만 정리하고 끝내려고 했던 글이... 점점 길어지고 있습니다. 생각해보니 아직 설명해야 할것들이 많이 남아 있네요. 위에서 잠깐 언급했던 ps라던가 tar, gzip등등... 시스템 관련된 것들입니다. 그리고, vi에 대해서도 알아봐야 하는데요. 이건 3부에서 알아보도록 하겠습니다.

     

    개발자에게 후원하기

    MGtdv7r.png

     

    추천, 구독, 홍보 꼭~ 부탁드립니다.

    여러분의 후원이 빠른 귀농을 가능하게 해줍니다~ 답답한 도시를 벗어나 귀농하고 싶은 개발자~

    감사합니다~

     

    • 네이버 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 카카오스토리 공유하기
    추천0 비추천0

    댓글목록

    등록된 댓글이 없습니다.