소개
이 실습에서는 텍스트 파일의 앞부분을 빠르게 확인할 수 있는 강력한 Linux 유틸리티인 head 명령어를 살펴봅니다. 수많은 파일을 빠르게 훑어보며 중요한 정보를 찾아야 하는 디지털 탐정이 되었다고 상상해 보세요. head 명령어는 파일 전체를 열지 않고도 앞부분을 들여다볼 수 있게 해주는 믿음직한 돋보기 역할을 합니다.
이번 실습에서는 바쁜 웹 서버에서 생성된 여러 로그 파일을 조사하는 상황을 가정합니다. 목표는 이러한 로그를 효율적으로 확인하여 잠재적인 문제를 찾아내고 유용한 정보를 얻는 것입니다. 실습을 진행하면서 head 명령어를 효과적으로 사용하는 방법을 익히고, 파일 탐색 작업을 더 빠르고 효율적으로 수행해 보겠습니다.
head 기본 사용법 이해하기
이 단계에서는 간단한 로그 파일을 살펴보며 head가 어떻게 동작하는지 알아봅니다.
먼저 프로젝트 디렉터리로 이동합니다.
cd /home/labex/project
이제 access.log라는 파일에 head 명령어를 실행해 보겠습니다.
head access.log
다음과 비슷한 출력이 표시됩니다.
192.168.1.100 - - [01/Jan/2024:00:00:01 +0000] "GET /index.html HTTP/1.1" 200 1234
192.168.1.101 - - [01/Jan/2024:00:00:02 +0000] "GET /style.css HTTP/1.1" 200 567
192.168.1.102 - - [01/Jan/2024:00:00:03 +0000] "GET /logo.png HTTP/1.1" 200 2345
192.168.1.103 - - [01/Jan/2024:00:00:04 +0000] "POST /login HTTP/1.1" 302 -
192.168.1.104 - - [01/Jan/2024:00:00:05 +0000] "GET /dashboard HTTP/1.1" 200 3456
192.168.1.105 - - [01/Jan/2024:00:00:06 +0000] "GET /api/user HTTP/1.1" 200 789
192.168.1.106 - - [01/Jan/2024:00:00:07 +0000] "GET /images/banner.jpg HTTP/1.1" 200 4567
192.168.1.107 - - [01/Jan/2024:00:00:08 +0000] "POST /comment HTTP/1.1" 201 -
192.168.1.108 - - [01/Jan/2024:00:00:09 +0000] "GET /search?q=linux HTTP/1.1" 200 2345
192.168.1.109 - - [01/Jan/2024:00:00:10 +0000] "GET /about HTTP/1.1" 200 1234
기본적으로 head는 파일의 처음 10줄을 표시합니다. 이 로그에서 각 줄은 웹 서버에 대한 하나의 요청을 나타내며, IP 주소, 타임스탬프, HTTP 메서드, 요청한 리소스, 상태 코드, 응답 크기 정보를 포함합니다.
표시할 줄 수 지정하기
이 단계에서는 head가 표시하는 줄 수를 직접 지정해 봅니다.
로그의 처음 5줄만 확인하려면 -n 옵션을 사용합니다.
head -n 5 access.log
다음과 같은 결과가 출력됩니다.
192.168.1.100 - - [01/Jan/2024:00:00:01 +0000] "GET /index.html HTTP/1.1" 200 1234
192.168.1.101 - - [01/Jan/2024:00:00:02 +0000] "GET /style.css HTTP/1.1" 200 567
192.168.1.102 - - [01/Jan/2024:00:00:03 +0000] "GET /logo.png HTTP/1.1" 200 2345
192.168.1.103 - - [01/Jan/2024:00:00:04 +0000] "POST /login HTTP/1.1" 302 -
192.168.1.104 - - [01/Jan/2024:00:00:05 +0000] "GET /dashboard HTTP/1.1" 200 3456
파일 앞부분의 특정 정보만 확인하고 처음 10줄 전체를 볼 필요가 없을 때 특히 유용합니다.
여러 파일 살펴보기
이 단계에서는 head를 사용해 여러 파일의 앞부분을 한 번에 확인합니다.
access.log와 error.log의 앞부분을 함께 살펴보겠습니다.
head access.log error.log
다음과 비슷한 출력이 표시됩니다.
==> access.log <==
192.168.1.120 - - [01/Jan/2024:00:00:53 +0000] "POST /about HTTP/1.1" 200 7616
192.168.1.147 - - [01/Jan/2024:00:00:45 +0000] "GET /dashboard HTTP/1.1" 200 7348
192.168.1.138 - - [01/Jan/2024:00:00:03 +0000] "DELETE /comment HTTP/1.1" 400 8341
192.168.1.138 - - [01/Jan/2024:00:00:31 +0000] "DELETE /about HTTP/1.1" 200 3254
192.168.1.122 - - [01/Jan/2024:00:00:15 +0000] "PUT /index.html HTTP/1.1" 500 6061
192.168.1.125 - - [01/Jan/2024:00:00:09 +0000] "DELETE /logo.png HTTP/1.1" 301 4916
192.168.1.148 - - [01/Jan/2024:00:00:33 +0000] "POST /admin/dashboard HTTP/1.1" 201 5546
192.168.1.146 - - [01/Jan/2024:00:00:56 +0000] "GET /images/banner.jpg HTTP/1.1" 301 2332
192.168.1.195 - - [01/Jan/2024:00:00:12 +0000] "DELETE /dashboard HTTP/1.1" 404 6740
192.168.1.136 - - [01/Jan/2024:00:00:18 +0000] "GET /login HTTP/1.1" 200 2374
==> error.log <==
[01/Jan/2024:00:01:23 +0000] [error] [client 192.168.1.150] File does not exist: /var/www/html/missing.html
[01/Jan/2024:00:02:34 +0000] [error] [client 192.168.1.151] PHP Parse error: syntax error, unexpected ';' in /var/www/html/index.php on line 30
[01/Jan/2024:00:03:45 +0000] [warn] [client 192.168.1.152] ModSecurity: Access denied with code 403 (phase 2). Matched phrase "sql injection attempt" at REQUEST_URI. [file "/etc/modsecurity/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf"] [line "50"] [id "942100"] [rev ""] [msg "SQL Injection Attack Detected via libinjection"] [data "Matched Data: SQL injection found within REQUEST_URI: /vulnerable.php?id=1'"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.0"] [maturity "0"] [accuracy "0"] [hostname "example.com"] [uri "/vulnerable.php"] [unique_id "YvKp2H8AAQEAAAxxBGIAAAAC"]
[01/Jan/2024:00:04:56 +0000] [error] [client 192.168.1.153] AH01071: Got error 'PHP message: PHP Fatal error: Uncaught Error: Call to undefined function mysql_connect() in /var/www/html/db.php:15...'
[01/Jan/2024:00:05:67 +0000] [warn] [client 192.168.1.154] ModSecurity: Warning. Matched "Operator \`Ge' with parameter \`5' against variable \`TX:ANOMALY_SCORE' (Value: \`5' ) [file "/etc/modsecurity/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "57"] [id "949110"] [rev ""] [msg "Inbound Anomaly Score Exceeded (Total Score: 5)"] [data ""] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.0"] [maturity "0"] [accuracy "0"] [hostname "example.com"] [uri "/admin"] [unique_id "YvKp2H8AAQEAAAxxBGIAAAAD"]
[01/Jan/2024:00:06:78 +0000] [error] [client 192.168.1.155] PCE: Can't open perl script "/var/www/html/cgi-bin/printenv": No such file or directory
[01/Jan/2024:00:07:89 +0000] [warn] [client 192.168.1.156] ModSecurity: Access denied with code 403 (phase 2). Matched phrase "directory traversal attempt" at ARGS:file. [file "/etc/modsecurity/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf"] [line "75"] [id "930110"] [rev ""] [msg "Path Traversal Attack (/../)"] [data "Matched Data: ../ found within ARGS:file: ../../../etc/passwd"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.0"] [maturity "0"] [accuracy "0"] [hostname "example.com"] [uri "/download.php"] [unique_id "YvKp2H8AAQEAAAxxBGIAAAAE"]
[01/Jan/2024:00:08:90 +0000] [error] [client 192.168.1.157] PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes) in /var/www/html/memory_hog.php on line 10
[01/Jan/2024:00:09:01 +0000] [warn] [client 192.168.1.158] ModSecurity: Warning. Pattern match "(?i:(?:[\s'\"`_''\(\)]*?(?:[\d\w]+[\s'\"`_''\(\)]*?){2,}[\s'\"`_''\(\)]*?(?:having|rongjitest|select|union|where|get_lst))" at ARGS:username. [file "/etc/modsecurity/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf"] [line "1126"] [id "942480"] [rev ""] [msg "SQL Injection Attack"] [data "Matched Data: union select found within ARGS:username: admin' UNION SELECT password FROM users--"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.0"] [maturity "0"] [accuracy "0"] [hostname "example.com"] [uri "/login.php"] [unique_id "YvKp2H8AAQEAAAxxBGIAAAAF"]
[01/Jan/2024:00:10:12 +0000] [error] [client 192.168.1.159] AH01797: client denied by server configuration: /var/www/html/restricted/
head는 각 파일의 출력을 헤더로 명확하게 구분해 줍니다. 여러 파일의 앞부분을 빠르게 비교해야 할 때 매우 유용합니다.
파이프와 함께 head 사용하기
이 단계에서는 파이프를 사용해 head를 다른 명령어와 결합합니다.
access.log의 처음 3줄에서 타임스탬프와 요청한 리소스에 해당하는 부분만 확인한다고 가정해 보겠습니다. cut 명령어를 head와 함께 사용하면 됩니다.
cut -d '"' -f2 access.log | head -n 3
다음과 같은 결과가 출력됩니다.
POST /about HTTP/1.1
GET /dashboard HTTP/1.1
DELETE /comment HTTP/1.1
cut -d '"' -f2 access.log 부분은 각 줄을 큰따옴표 기준으로 나눈 뒤 두 번째 필드를 선택합니다. 이 필드에는 HTTP 요청이 들어 있습니다. |는 이렇게 얻은 결과를 head -n 3으로 전달하고, head는 그중 처음 3줄만 표시합니다.
이 조합을 사용하면 로그 항목에서 필요한 부분에 빠르게 집중할 수 있어 조사 작업을 더욱 효율적으로 진행할 수 있습니다.
head와 grep으로 조사하기
이 단계에서는 head와 grep을 결합해 로그에서 특정 패턴을 검색합니다.
/admin 페이지와 관련된 비정상적인 활동이 보고되었다고 가정해 보겠습니다. 액세스 로그에서 /admin이 포함된 항목 중 처음 몇 개를 확인하려면 다음 명령어를 사용합니다.
grep "/admin" access.log | head -n 3
다음과 비슷한 결과가 출력됩니다.
192.168.1.148 - - [01/Jan/2024:00:00:33 +0000] "POST /admin/dashboard HTTP/1.1" 201 5546
192.168.1.115 - - [01/Jan/2024:00:00:22 +0000] "PUT /admin HTTP/1.1" 302 1113
192.168.1.163 - - [01/Jan/2024:00:00:56 +0000] "POST /admin/dashboard HTTP/1.1" 301 815
grep "/admin" access.log 부분은 access.log에서 /admin이 포함된 줄을 검색합니다. |는 검색 결과를 head -n 3으로 전달하고, head는 일치하는 항목 중 처음 3개만 표시합니다.
이 조합을 사용하면 로그 파일에서 관련 항목만 빠르게 추려낼 수 있으므로, 보다 집중적이고 효율적으로 조사할 수 있습니다.
head로 대용량 파일 탐색하기
이 단계에서는 파일 전체를 메모리에 불러오지 않고 head를 사용해 대용량 로그 파일을 살펴봅니다.
지금까지 사용한 access.log 파일을 이용해 대용량 파일을 다루는 상황을 시뮬레이션해 보겠습니다. 실제 파일보다 훨씬 큰 파일이라고 가정합니다.
먼저 파일 크기를 확인합니다.
ls -lh access.log
이제 head를 사용해 처음 15줄을 확인합니다.
head -n 15 access.log
앞에서 본 것과 비슷한 결과가 표시되지만, 10줄이 아니라 15줄이 출력됩니다.
head 명령어는 파일의 앞부분만 읽기 때문에 빠르게 동작하며, 파일 전체를 메모리에 적재하지 않으므로 메모리 효율도 높습니다. 따라서 파일의 구조와 내용을 빠르게 파악할 수 있습니다.
요약
이번 실습에서는 파일의 앞부분을 빠르게 확인할 수 있는 강력한 도구인 head 명령어를 살펴보았습니다. 다음과 같은 내용을 학습했습니다.
- 기본 설정으로
head를 사용해 파일의 처음 10줄을 확인하는 방법 -n옵션으로 표시할 줄 수를 지정하는 방법head로 여러 파일을 동시에 살펴보는 방법- 파이프를 사용해
head를cut,grep과 같은 다른 명령어와 결합하는 방법 head를 사용해 대용량 파일을 효율적으로 다루는 방법
이번 실습에서 다루지 않은 추가 head 옵션:
-c: 줄이 아닌 파일의 처음 몇 바이트를 표시합니다.-q: 여러 파일을 확인할 때 헤더를 표시하지 않습니다.-v: 여러 파일을 확인할 때 항상 헤더를 표시합니다.



