[ { "id": "linux-q29", "lesson_id": "linux-passwd", "question_type": "multiple_choice", "question": "`passwd -l devuser`의 의미로 가장 맞는 것은?", "options": [ "devuser 계정을 잠가 비밀번호 로그인을 막는다", "devuser 비밀번호를 강제 만료시킨다", "devuser 계정을 완전히 삭제한다", "devuser 비밀번호를 빈 값으로 초기화한다" ], "answer": "devuser 계정을 잠가 비밀번호 로그인을 막는다", "explanation": "`passwd -l`은 계정을 잠가 해당 사용자가 비밀번호로 로그인할 수 없게 합니다. 잠금 해제는 `passwd -u`입니다.", "difficulty": "easy", "source_id": "ubuntu-user-management" }, { "id": "linux-q30", "lesson_id": "linux-groups-id", "question_type": "multiple_choice", "question": "현재 사용자의 UID, GID, 보조 그룹 목록을 한 번에 확인하는 명령은?", "options": [ "id", "groups", "whoami", "ls -l" ], "answer": "id", "explanation": "`id`는 UID, GID, 속한 그룹 목록을 모두 보여줍니다. `groups`는 그룹 이름만, `whoami`는 사용자 이름만 보여줍니다.", "difficulty": "easy", "source_id": "ubuntu-user-management" }, { "id": "linux-q31", "lesson_id": "linux-acl", "question_type": "multiple_choice", "question": "파일에 설정된 ACL 권한 내역을 확인하는 명령은?", "options": [ "getfacl", "setfacl", "chmod", "ls -l" ], "answer": "getfacl", "explanation": "`getfacl`로 현재 ACL 설정을 확인합니다. `setfacl -m`으로 ACL을 설정합니다. `ls -l`만으로는 ACL 전체가 보이지 않습니다.", "difficulty": "easy", "source_id": "manual-linux-basic" }, { "id": "linux-q32", "lesson_id": "linux-ssh", "question_type": "multiple_choice", "question": "SSH 접속 실패 원인으로 관련이 없는 것은?", "options": [ "사용자의 Python 버전", "SSH 서비스 실행 여부", "방화벽 22번 포트 허용 여부", "authorized_keys 파일 권한" ], "answer": "사용자의 Python 버전", "explanation": "SSH 접속은 서비스 실행, 방화벽, 키 파일 권한이 모두 맞아야 합니다. Python 버전은 SSH 접속과 무관합니다.", "difficulty": "easy", "source_id": "ubuntu-server-docs" }, { "id": "linux-q33", "lesson_id": "linux-hostname-hosts", "question_type": "multiple_choice", "question": "`/etc/hosts` 파일의 주된 역할은?", "options": [ "DNS 조회 전에 참조되는 로컬 이름 해석 파일이다", "방화벽 규칙을 저장한다", "사용자 비밀번호를 저장한다", "swap 공간을 정의한다" ], "answer": "DNS 조회 전에 참조되는 로컬 이름 해석 파일이다", "explanation": "`/etc/hosts`는 DNS 조회보다 먼저 참조되는 로컬 이름 해석 파일입니다. 테스트 환경이나 특정 호스트 이름 재정의에 자주 씁니다.", "difficulty": "easy", "source_id": "ubuntu-networking" }, { "id": "linux-q34", "lesson_id": "linux-netplan", "question_type": "multiple_choice", "question": "Ubuntu에서 netplan 네트워크 설정을 시스템에 적용하는 명령은?", "options": [ "sudo netplan apply", "sudo ifconfig apply", "sudo ip apply", "sudo ufw apply" ], "answer": "sudo netplan apply", "explanation": "`sudo netplan apply`는 `/etc/netplan/*.yaml` 설정을 파싱해 시스템에 적용합니다. YAML 들여쓰기 오류가 있으면 실패합니다.", "difficulty": "easy", "source_id": "ubuntu-networking" }, { "id": "linux-q35", "lesson_id": "linux-curl", "question_type": "multiple_choice", "question": "`curl -I https://example.com`의 `-I` 옵션 역할은?", "options": [ "HTTP 헤더만 요청해 응답 상태를 확인한다", "데이터를 POST로 전송한다", "SSL 인증서 검증을 건너뛴다", "JSON 형식으로만 출력한다" ], "answer": "HTTP 헤더만 요청해 응답 상태를 확인한다", "explanation": "`-I`는 HEAD 요청을 보내 응답 헤더만 받습니다. 서비스가 올바른 상태 코드를 반환하는지 빠르게 확인할 때 유용합니다.", "difficulty": "easy", "source_id": "ubuntu-networking" }, { "id": "linux-q36", "lesson_id": "linux-ping", "question_type": "multiple_choice", "question": "ping이 성공하더라도 보장되지 않는 것은?", "options": [ "HTTP 서비스가 정상 동작하는 것", "ICMP 통신이 가능하다는 것", "네트워크 경로가 있다는 것", "IP 통신이 가능하다는 것" ], "answer": "HTTP 서비스가 정상 동작하는 것", "explanation": "ping은 ICMP 응답만 확인합니다. 방화벽이 ICMP를 허용해도 HTTP 서비스가 내려가 있을 수 있고, 반대로 HTTP가 되어도 ICMP가 막힐 수 있습니다.", "difficulty": "easy", "source_id": "ubuntu-networking" }, { "id": "linux-q37", "lesson_id": "linux-top", "question_type": "multiple_choice", "question": "`top` 명령어가 가장 적합한 상황은?", "options": [ "CPU/메모리 사용량이 높은 프로세스를 실시간으로 확인할 때", "파일 이름 패턴으로 검색할 때", "패키지를 설치할 때", "파일시스템 사용량을 볼 때" ], "answer": "CPU/메모리 사용량이 높은 프로세스를 실시간으로 확인할 때", "explanation": "`top`은 CPU, 메모리 사용량과 프로세스 목록을 실시간으로 갱신해 보여줍니다. 서버 부하 원인 파악에 자주 씁니다.", "difficulty": "easy", "source_id": "ubuntu-server-docs" }, { "id": "linux-q38", "lesson_id": "linux-nice", "question_type": "multiple_choice", "question": "`nice -n 10 command`에서 nice 값이 높을수록 어떻게 되는가?", "options": [ "다른 프로세스에 CPU를 양보하는 낮은 우선순위를 가진다", "CPU 코어를 더 많이 사용한다", "지정된 분 후에 실행된다", "메모리를 더 많이 차지한다" ], "answer": "다른 프로세스에 CPU를 양보하는 낮은 우선순위를 가진다", "explanation": "nice 값이 높을수록 다른 프로세스에게 CPU를 더 양보합니다. 범위는 -20(가장 높은 우선순위)에서 19(가장 낮은 우선순위)입니다.", "difficulty": "easy", "source_id": "ubuntu-server-docs" }, { "id": "linux-q39", "lesson_id": "linux-swap", "question_type": "multiple_choice", "question": "swap 사용량이 매우 높을 때 시스템 상태를 가장 잘 나타내는 것은?", "options": [ "물리 메모리가 부족해 디스크를 보조 메모리로 사용하고 있다", "CPU가 과부하 상태다", "디스크 공간이 꽉 찼다", "네트워크 연결이 끊겼다" ], "answer": "물리 메모리가 부족해 디스크를 보조 메모리로 사용하고 있다", "explanation": "swap 과사용은 물리 RAM 부족의 신호입니다. 디스크가 RAM보다 훨씬 느려서 swap 과다 사용은 심각한 성능 저하로 이어집니다.", "difficulty": "easy", "source_id": "ubuntu-storage" }, { "id": "linux-q40", "lesson_id": "linux-lvm", "question_type": "multiple_choice", "question": "LVM에서 물리 볼륨(PV)들이 합쳐지는 중간 계층은?", "options": [ "Volume Group (VG)", "Logical Volume (LV)", "/etc/fstab", "partition table" ], "answer": "Volume Group (VG)", "explanation": "LVM 계층은 PV(물리 볼륨) → VG(볼륨 그룹) → LV(논리 볼륨) 순입니다. VG는 PV들을 묶고, LV는 VG에서 용량을 나눠 씁니다.", "difficulty": "easy", "source_id": "ubuntu-storage" }, { "id": "linux-q41", "lesson_id": "linux-logs-var", "question_type": "multiple_choice", "question": "`/var/log` 디렉터리에서 주로 볼 수 있는 것은?", "options": [ "서비스, 인증, 시스템의 로그 파일", "사용자 홈 디렉터리", "실행 가능한 패키지 바이너리", "네트워크 설정 파일" ], "answer": "서비스, 인증, 시스템의 로그 파일", "explanation": "`/var/log`는 nginx, syslog, auth.log, kern.log 같은 다양한 로그 파일이 모이는 표준 위치입니다.", "difficulty": "easy", "source_id": "ubuntu-server-docs" }, { "id": "linux-q42", "lesson_id": "linux-dmesg", "question_type": "multiple_choice", "question": "`dmesg | tail`로 확인하기에 가장 적합한 정보는?", "options": [ "부팅과 하드웨어 관련 커널 메시지", "HTTP 서버 접속 로그", "사용자 비밀번호 정책", "cron 실행 이력" ], "answer": "부팅과 하드웨어 관련 커널 메시지", "explanation": "`dmesg`는 커널 링 버퍼를 출력합니다. 부팅 과정, 하드웨어 감지, 드라이버 오류 같은 시스템 수준 메시지를 볼 때 유용합니다.", "difficulty": "easy", "source_id": "ubuntu-server-docs" }, { "id": "linux-q43", "lesson_id": "linux-env-path", "question_type": "multiple_choice", "question": "cron 작업이 터미널에서는 되지만 cron에서만 실패할 때 먼저 의심할 원인은?", "options": [ "PATH 환경 변수가 cron과 터미널에서 다르다", "디스크 공간이 부족하다", "SSH 키 파일이 없다", "systemctl이 중지됐다" ], "answer": "PATH 환경 변수가 cron과 터미널에서 다르다", "explanation": "cron은 로그인 shell보다 훨씬 제한된 PATH를 씁니다. 스크립트에서 절대 경로를 사용하거나 crontab에서 PATH를 직접 설정하면 해결됩니다.", "difficulty": "easy", "source_id": "linux-bash-cd" }, { "id": "linux-q44", "lesson_id": "linux-wildcard", "question_type": "multiple_choice", "question": "`ls *.log` 명령에서 `*.log` 패턴을 파일 목록으로 확장하는 주체는?", "options": [ "Shell (bash/zsh)", "ls 명령어 자체", "kernel", "파일시스템 드라이버" ], "answer": "Shell (bash/zsh)", "explanation": "와일드카드 글로빙(glob)은 shell이 명령 실행 전에 파일명 목록으로 확장합니다. ls가 아니라 shell이 처리합니다.", "difficulty": "easy", "source_id": "linux-bash-cd" }, { "id": "linux-q45", "lesson_id": "linux-service-port", "question_type": "multiple_choice", "question": "`systemctl is-active nginx`가 active인데도 80포트에 연결이 안 될 때 확인 대상이 아닌 것은?", "options": [ "사용자의 SSH 공개 키", "방화벽 80포트 허용 여부", "nginx가 80포트에서 listen 중인지", "nginx 설정 파일 문법 오류" ], "answer": "사용자의 SSH 공개 키", "explanation": "서비스가 active여도 방화벽, 포트 listen 설정, 설정 파일 오류로 연결이 안 될 수 있습니다. SSH 공개 키는 80포트 연결과 무관합니다.", "difficulty": "easy", "source_id": "linux-man7-ip" }, { "id": "linux-q46", "lesson_id": "linux-repo", "question_type": "multiple_choice", "question": "`apt update` 실행 시 특정 repository에서 오류가 날 때 먼저 의심할 원인은?", "options": [ "repository URL이나 GPG 키 설정 문제", "CPU 온도가 높다", "swap 공간이 부족하다", "실행 중인 프로세스 수가 많다" ], "answer": "repository URL이나 GPG 키 설정 문제", "explanation": "`apt update` 실패는 repository URL 오류, 네트워크 차단, GPG 서명 키 문제가 주된 원인입니다.", "difficulty": "easy", "source_id": "ubuntu-package-management" }, { "id": "linux-q47", "lesson_id": "linux-head-tail", "question_type": "multiple_choice", "question": "증가하는 로그 파일을 실시간으로 계속 추적하는 명령으로 가장 적합한 것은?", "options": [ "tail -f /var/log/syslog", "head -f /var/log/syslog", "cat -f /var/log/syslog", "watch /var/log/syslog" ], "answer": "tail -f /var/log/syslog", "explanation": "`tail -f`는 파일 끝에 추가되는 내용을 실시간으로 계속 보여줍니다. 로그 모니터링에 가장 많이 씁니다.", "difficulty": "easy", "source_id": "manual-linux-basic" }, { "id": "linux-q48", "lesson_id": "linux-sed", "question_type": "multiple_choice", "question": "`sed 's/old/new/g' file.txt`의 역할은?", "options": [ "file.txt의 old를 모두 new로 교체해 표준 출력으로 보낸다", "file.txt를 정렬해 출력한다", "file.txt에서 old 줄을 삭제한다", "file.txt를 새 파일로 복사한다" ], "answer": "file.txt의 old를 모두 new로 교체해 표준 출력으로 보낸다", "explanation": "`sed 's/패턴/교체/g'`는 파일에서 패턴을 찾아 교체한 결과를 출력합니다. `-i` 없이는 원본 파일을 바꾸지 않습니다.", "difficulty": "easy", "source_id": "manual-linux-basic" }, { "id": "linux-q49", "lesson_id": "linux-text-pipeline", "question_type": "multiple_choice", "question": "파일 전체에서 중복 줄을 제거하려 할 때 `uniq` 전에 일반적으로 필요한 명령은?", "options": [ "sort", "cut", "wc", "grep" ], "answer": "sort", "explanation": "`uniq`은 연속된 중복 줄만 제거합니다. 파일 전체에서 중복을 제거하려면 먼저 `sort`로 정렬한 뒤 `uniq`을 적용해야 합니다.", "difficulty": "easy", "source_id": "manual-linux-basic" }, { "id": "linux-q50", "lesson_id": "linux-awk", "question_type": "multiple_choice", "question": "`awk '{print $2}' access.log`가 하는 일은?", "options": [ "각 줄의 두 번째 필드를 출력한다", "두 번째 줄만 출력한다", "두 번째 파일을 연다", "필드 구분자를 2번으로 바꾼다" ], "answer": "각 줄의 두 번째 필드를 출력한다", "explanation": "awk에서 `$1`, `$2`, `$N`은 공백으로 구분된 각 필드를 의미합니다. `$2`는 각 줄의 두 번째 필드를 출력합니다.", "difficulty": "easy", "source_id": "manual-linux-basic" }, { "id": "linux-q51", "lesson_id": "linux-ln-symlink", "question_type": "multiple_choice", "question": "`ln -s /etc/nginx/nginx.conf ~/nginx.conf`로 만들어지는 것은?", "options": [ "nginx.conf를 가리키는 심볼릭 링크", "nginx.conf의 하드 복사본", "nginx.conf라는 디렉터리", "nginx.conf의 이름만 변경한 것" ], "answer": "nginx.conf를 가리키는 심볼릭 링크", "explanation": "`ln -s`는 원본 파일을 가리키는 심볼릭 링크를 만듭니다. `ls -l`에서 `->` 표시로 확인할 수 있습니다.", "difficulty": "easy", "source_id": "manual-linux-basic" }, { "id": "linux-q52", "lesson_id": "linux-bg-fg-jobs", "question_type": "multiple_choice", "question": "터미널이 닫혀도 작업이 계속 실행되도록 백그라운드로 실행하는 명령은?", "options": [ "nohup long-command &", "long-command &", "bg long-command", "jobs -r long-command" ], "answer": "nohup long-command &", "explanation": "`nohup`은 터미널 종료 시 보내는 HUP 시그널을 무시해 작업이 계속 실행되도록 합니다. `&`만으로는 터미널이 닫히면 작업이 종료됩니다.", "difficulty": "easy", "source_id": "ubuntu-server-docs" }, { "id": "linux-q53", "lesson_id": "linux-shell-script-basics", "question_type": "multiple_choice", "question": "쉘 스크립트에서 스크립트에 전달된 첫 번째 인수를 참조하는 변수는?", "options": [ "$1", "$0", "$@", "$$" ], "answer": "$1", "explanation": "`$0`은 스크립트 이름, `$1`은 첫 번째 인수, `$@`는 모든 인수 목록, `$$`는 현재 프로세스 PID입니다.", "difficulty": "easy", "source_id": "linux-bash-cd" }, { "id": "linux-q54", "lesson_id": "linux-ls", "question_type": "multiple_choice", "question": "숨김 파일을 포함해 상세 정보를 보는 ls 옵션 조합은?", "options": [ "ls -rh", "ls -al", "ls -d", "ls -t" ], "answer": "ls -al", "explanation": "`-a`는 점으로 시작하는 숨김 파일 포함, `-l`은 권한·소유자·크기·날짜를 포함한 긴 형식 출력입니다.", "source_id": "manual-linux-basic", "difficulty": "easy" }, { "id": "linux-q55", "lesson_id": "linux-cd", "question_type": "multiple_choice", "question": "`cd -` 명령어의 결과는?", "options": [ "루트 디렉터리로 이동", "이전 디렉터리로 이동", "홈 디렉터리로 이동", "상위 디렉터리로 이동" ], "answer": "이전 디렉터리로 이동", "explanation": "`cd -`는 OLDPWD에 저장된 직전 디렉터리로 돌아갑니다. 두 디렉터리 사이를 빠르게 오갈 때 유용합니다.", "source_id": "manual-linux-basic", "difficulty": "easy" }, { "id": "linux-q56", "lesson_id": "linux-cat", "question_type": "multiple_choice", "question": "파일 내용을 줄 번호와 함께 출력하는 cat 옵션은?", "options": [ "-n", "-v", "-e", "-s" ], "answer": "-n", "explanation": "`cat -n`은 모든 줄에 번호를 붙여 출력합니다. 스크립트 디버깅이나 특정 줄 위치 확인에 유용합니다.", "source_id": "manual-linux-basic", "difficulty": "easy" }, { "id": "linux-q57", "lesson_id": "linux-process-ps-kill", "question_type": "multiple_choice", "question": "실행 중인 모든 프로세스를 사용자 이름과 함께 전체 목록으로 보는 명령은?", "options": [ "ps aux", "ps -e", "top -n1", "kill -l" ], "answer": "ps aux", "explanation": "`ps aux`는 모든 사용자의 전체 프로세스를 CPU/메모리 사용량과 함께 보여줍니다. 시험에서 가장 자주 쓰이는 ps 옵션 조합입니다.", "source_id": "manual-linux-basic", "difficulty": "easy" }, { "id": "linux-q58", "lesson_id": "linux-cp-mv-rm", "question_type": "multiple_choice", "question": "운영 중인 서버의 `/etc/nginx/nginx.conf`를 수정하기 전 권한과 타임스탬프를 보존해 같은 디렉터리에 백업하려 합니다. 올바른 명령은?", "options": [ "cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak", "cp -a /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak", "cp -r /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak", "mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak" ], "answer": "cp -a /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak", "explanation": "`cp -a`는 권한·소유자·타임스탬프를 모두 보존합니다(`-dR --preserve=all`). `-r`은 디렉터리 재귀 복사용이며 속성을 보존하지 않습니다. `mv`는 원본이 사라집니다.", "source_id": "manual-linux-basic", "difficulty": "medium" }, { "id": "linux-q59", "lesson_id": "linux-cp-mv-rm", "question_type": "multiple_choice", "question": "`rm -rf /var/log/old/`를 실행했을 때 발생하는 일은?", "options": [ "/var/log/old/ 디렉터리와 하위 모든 파일이 즉시 삭제된다", "각 파일마다 삭제 확인을 요청한다", "/var/log/old/가 휴지통으로 이동한다", "심볼릭 링크만 삭제하고 실제 파일은 남긴다" ], "answer": "/var/log/old/ 디렉터리와 하위 모든 파일이 즉시 삭제된다", "explanation": "`-r`은 재귀 삭제, `-f`는 확인 없이 강제 삭제입니다. 리눅스에는 휴지통이 없어 복구가 매우 어렵습니다. 중요 경로에서는 먼저 `ls`로 대상을 확인하세요.", "source_id": "manual-linux-basic", "difficulty": "easy" }, { "id": "linux-q60", "lesson_id": "linux-fdisk-parted", "question_type": "multiple_choice", "question": "3TB 용량의 새 디스크 `/dev/sdc`에 파티션을 만들 때 fdisk 대신 parted를 사용해야 하는 이유는?", "options": [ "fdisk는 MBR 방식으로 2TB 초과 디스크를 지원하지 않기 때문", "parted가 더 빠르기 때문", "fdisk는 ext4 파일시스템만 지원하기 때문", "parted만 RAID 설정을 지원하기 때문" ], "answer": "fdisk는 MBR 방식으로 2TB 초과 디스크를 지원하지 않기 때문", "explanation": "MBR 파티션 테이블은 최대 2TB를 지원합니다. 3TB 디스크는 GPT가 필요하며 `parted`나 `gdisk`로 GPT 테이블을 생성해야 합니다.", "source_id": "manual-linux-storage", "difficulty": "medium" }, { "id": "linux-q61", "lesson_id": "linux-fdisk-parted", "question_type": "multiple_choice", "question": "`fdisk /dev/sdb` 실행 후 새 주 파티션을 만들고 저장하는 키 순서는?", "options": [ "n → p → w", "p → n → w", "n → e → q", "w → n → p" ], "answer": "n → p → w", "explanation": "`n`(new partition) → `p`(primary) → 번호·섹터 입력 → `w`(write & quit). `q`는 저장 없이 종료, `p`는 현재 테이블 출력(Print)이기도 합니다.", "source_id": "manual-linux-storage", "difficulty": "medium" }, { "id": "linux-q62", "lesson_id": "linux-mkfs-fsck", "question_type": "multiple_choice", "question": "다음 스토리지 설정 순서 중 올바른 것은?", "options": [ "파티션 생성 → 파일시스템 생성(mkfs) → 마운트 포인트 생성 → mount", "마운트 → mkfs → 파티션 생성 → fstab 등록", "mkfs → 파티션 생성 → mount → fstab 등록", "파티션 생성 → mount → mkfs → fstab 등록" ], "answer": "파티션 생성 → 파일시스템 생성(mkfs) → 마운트 포인트 생성 → mount", "explanation": "fdisk로 파티션 생성 → mkfs로 포맷 → mkdir로 마운트 포인트 생성 → mount로 연결이 올바른 순서입니다. 영구 마운트는 마지막에 fstab에 등록합니다.", "source_id": "manual-linux-storage", "difficulty": "medium" }, { "id": "linux-q63", "lesson_id": "linux-mkfs-fsck", "question_type": "multiple_choice", "question": "마운트된 파일시스템에서 `fsck`를 실행하면 어떻게 되는가?", "options": [ "데이터 손상이 발생할 수 있다", "자동으로 언마운트 후 검사한다", "읽기 전용으로 전환 후 검사한다", "정상적으로 오류를 수정한다" ], "answer": "데이터 손상이 발생할 수 있다", "explanation": "`fsck`는 언마운트된 파일시스템에서만 실행해야 합니다. 마운트 상태에서 실행하면 OS와 fsck가 동시에 파일시스템에 쓰기를 시도해 데이터가 손상될 수 있습니다.", "source_id": "manual-linux-storage", "difficulty": "medium" }, { "id": "linux-q64", "lesson_id": "linux-groupadd", "question_type": "multiple_choice", "question": "`usermod -G developers alice`를 `-a` 없이 실행했을 때 발생하는 문제는?", "options": [ "alice의 기존 보조 그룹이 모두 제거되고 developers만 남는다", "alice가 developers 그룹에서 제거된다", "명령이 실패하고 오류가 출력된다", "alice의 기본 그룹이 developers로 변경된다" ], "answer": "alice의 기존 보조 그룹이 모두 제거되고 developers만 남는다", "explanation": "`-G`는 보조 그룹을 지정한 목록으로 교체합니다. 기존 그룹을 유지하면서 추가하려면 반드시 `-aG`(append)를 사용해야 합니다.", "source_id": "ubuntu-user-management", "difficulty": "medium" }, { "id": "linux-q65", "lesson_id": "linux-chage", "question_type": "multiple_choice", "question": "신규 입사자 bob이 첫 로그인 시 반드시 비밀번호를 변경하게 하려 합니다. 적절한 명령은?", "options": [ "chage -d 0 bob", "chage -M 0 bob", "passwd -l bob", "chage -E 0 bob" ], "answer": "chage -d 0 bob", "explanation": "`chage -d 0`은 마지막 비밀번호 변경일을 에포크(1970-01-01)로 설정해 다음 로그인 시 즉시 변경을 강제합니다. `-E 0`은 계정 자체를 만료시켜 로그인을 차단합니다.", "source_id": "ubuntu-user-management", "difficulty": "medium" }, { "id": "linux-q66", "lesson_id": "linux-chage", "question_type": "multiple_choice", "question": "보안 정책상 모든 사용자가 90일마다 비밀번호를 바꿔야 합니다. alice에게 적용하는 명령은?", "options": [ "chage -M 90 alice", "chage -d 90 alice", "passwd -M 90 alice", "chage -W 90 alice" ], "answer": "chage -M 90 alice", "explanation": "`-M`은 비밀번호 최대 사용 기간(Maximum days)을 설정합니다. `-W`는 만료 전 경고일, `-d`는 마지막 변경일, `-E`는 계정 만료일입니다.", "source_id": "ubuntu-user-management", "difficulty": "medium" }, { "id": "linux-q67", "lesson_id": "linux-systemd-unit", "question_type": "multiple_choice", "question": "`/etc/systemd/system/myapp.service` 파일을 수정한 뒤 변경 사항을 적용하는 올바른 순서는?", "options": [ "systemctl daemon-reload → systemctl restart myapp", "systemctl restart myapp → systemctl daemon-reload", "reboot → systemctl restart myapp", "systemctl reload myapp만 실행" ], "answer": "systemctl daemon-reload → systemctl restart myapp", "explanation": "유닛 파일 수정 후 systemd가 변경을 인식하려면 `daemon-reload`가 먼저 필요합니다. 그 다음 `restart`로 서비스를 재시작해야 새 설정이 적용됩니다.", "source_id": "manual-linux-systemd", "difficulty": "medium" }, { "id": "linux-q68", "lesson_id": "linux-systemd-unit", "question_type": "multiple_choice", "question": "서비스 유닛 파일에서 `WantedBy=multi-user.target`의 역할은?", "options": [ "systemctl enable 시 multi-user.target 실행 단계에서 서비스가 자동 시작되도록 등록한다", "서비스가 multi-user 이후에만 중지됨을 의미한다", "서비스를 그래픽 환경에서만 실행하게 한다", "다른 서비스보다 먼저 시작하게 한다" ], "answer": "systemctl enable 시 multi-user.target 실행 단계에서 서비스가 자동 시작되도록 등록한다", "explanation": "`WantedBy`는 `systemctl enable` 실행 시 어느 target의 `.wants/` 디렉터리에 심볼릭 링크를 생성할지 결정합니다. `multi-user.target`은 네트워크 서비스가 준비된 CLI 환경(runlevel 3)입니다.", "source_id": "manual-linux-systemd", "difficulty": "easy" }, { "id": "linux-q69", "lesson_id": "linux-at", "question_type": "multiple_choice", "question": "매일 반복이 아닌 내일 새벽 3시에 한 번만 백업 스크립트를 실행하려 합니다. 적절한 도구는?", "options": [ "at", "cron", "systemd timer", "nohup" ], "answer": "at", "explanation": "`at`은 일회성 예약 실행을 위한 도구입니다. cron은 반복 스케줄에 적합하고, nohup은 터미널 종료 후에도 프로세스를 유지하기 위한 도구로 스케줄링 기능은 없습니다.", "source_id": "manual-linux-basic", "difficulty": "medium" }, { "id": "linux-q70", "lesson_id": "linux-docker-basics", "question_type": "multiple_choice", "question": "nginx 컨테이너를 백그라운드로 실행하고 호스트 포트 8080을 컨테이너 포트 80에 연결하는 명령은?", "options": [ "docker run -d -p 8080:80 nginx", "docker run -p 80:8080 nginx", "docker start -p 8080:80 nginx", "docker run --port 8080=80 -b nginx" ], "answer": "docker run -d -p 8080:80 nginx", "explanation": "`-d`는 detach(백그라운드), `-p 호스트포트:컨테이너포트`로 포트를 매핑합니다. `8080:80`은 호스트의 8080을 컨테이너의 80으로 포워딩합니다.", "source_id": "manual-linux-docker", "difficulty": "medium" }, { "id": "linux-q71", "lesson_id": "linux-docker-basics", "question_type": "multiple_choice", "question": "실행 중이거나 중지된 모든 컨테이너 목록을 보는 명령은?", "options": [ "docker ps -a", "docker ps", "docker images", "docker container ls" ], "answer": "docker ps -a", "explanation": "`docker ps`는 실행 중인 컨테이너만 표시합니다. `-a`(all) 플래그를 추가하면 중지된 컨테이너까지 모두 표시합니다.", "source_id": "manual-linux-docker", "difficulty": "easy" }, { "id": "linux-q72", "lesson_id": "linux-grub-boot", "question_type": "multiple_choice", "question": "`/etc/default/grub`에서 `GRUB_TIMEOUT=10`으로 변경 후 적용하는 명령은? (Ubuntu 기준)", "options": [ "update-grub", "grub-install", "systemctl restart grub", "reboot" ], "answer": "update-grub", "explanation": "`/etc/default/grub`은 템플릿 역할을 하며, `update-grub`(Ubuntu) 또는 `grub2-mkconfig -o /boot/grub2/grub.cfg`(RHEL)를 실행해야 실제 GRUB 설정 파일에 반영됩니다.", "source_id": "manual-linux-boot", "difficulty": "medium" }, { "id": "linux-q73", "lesson_id": "linux-grub-boot", "question_type": "multiple_choice", "question": "시스템이 그래픽 환경 없이 CLI 다중 사용자 모드로 기본 부팅되게 하는 명령은?", "options": [ "systemctl set-default multi-user.target", "systemctl set-default graphical.target", "update-grub --target=cli", "systemctl disable gdm" ], "answer": "systemctl set-default multi-user.target", "explanation": "`multi-user.target`은 GUI 없이 네트워크와 다중 사용자 환경을 제공하는 target(runlevel 3 상당)입니다. `graphical.target`(runlevel 5)에서 변경하면 다음 재시작부터 CLI로 부팅됩니다.", "source_id": "manual-linux-boot", "difficulty": "medium" }, { "id": "linux-q74", "lesson_id": "linux-find", "question_type": "multiple_choice", "question": "7일 이상 수정되지 않은 `/var/log`의 `.log` 파일을 찾아 일괄 삭제하려 합니다. 올바른 명령은?", "options": [ "find /var/log -name '*.log' -mtime +7 -delete", "find /var/log -name '*.log' -mtime 7 -rm", "grep -r '.log' /var/log | xargs rm", "ls -lt /var/log/*.log | tail -n +8 | xargs rm" ], "answer": "find /var/log -name '*.log' -mtime +7 -delete", "explanation": "`-mtime +7`은 마지막 수정 후 7일 초과된 파일, `-delete`는 find 내장 삭제 액션입니다. `-mtime 7`(정확히 7일)과 `-mtime +7`(7일 초과)의 차이에 주의하세요.", "source_id": "manual-linux-basic", "difficulty": "hard" }, { "id": "linux-q75", "lesson_id": "linux-pipe-redirect", "question_type": "multiple_choice", "question": "`ls /notexist 2>/dev/null && echo OK`의 실행 결과는?", "options": [ "아무것도 출력되지 않는다", "OK가 출력된다", "오류 메시지가 출력된다", "OK와 오류 메시지가 함께 출력된다" ], "answer": "아무것도 출력되지 않는다", "explanation": "`2>/dev/null`로 stderr를 버리고, `ls /notexist`가 실패(exit code != 0)하므로 `&&` 뒤의 `echo OK`는 실행되지 않습니다. 결과적으로 아무것도 출력되지 않습니다.", "source_id": "manual-linux-basic", "difficulty": "medium" }, { "id": "linux-q76", "lesson_id": "linux-systemctl", "question_type": "multiple_choice", "question": "서버 재시작 후에도 nginx가 자동으로 시작되게 하려 합니다. 현재 실행 중이며 enable만 빠진 상태입니다. 필요한 명령은?", "options": [ "systemctl enable nginx", "systemctl start nginx", "systemctl enable --now nginx", "systemctl restart nginx" ], "answer": "systemctl enable nginx", "explanation": "이미 실행 중이므로 `start`는 불필요합니다. `enable`만 하면 부팅 시 자동 시작 심볼릭 링크가 생성됩니다. `enable --now`는 enable + start를 동시에 처리합니다.", "source_id": "manual-linux-basic", "difficulty": "easy" }, { "id": "linux-q77", "lesson_id": "linux-acl", "question_type": "multiple_choice", "question": "`/project` 디렉터리를 `devteam` 그룹 멤버 모두가 읽고 쓸 수 있게 하고, 새로 생성된 파일도 같은 그룹 소유가 되게 하는 설정은?", "options": [ "chmod 2775 /project && chgrp devteam /project", "chmod 777 /project", "setfacl -m g:devteam:rw /project", "chown devteam /project && chmod 755 /project" ], "answer": "chmod 2775 /project && chgrp devteam /project", "explanation": "`2775`의 앞 자리 2는 SGID(Set Group ID) 비트입니다. SGID가 설정된 디렉터리에서 생성된 파일은 자동으로 디렉터리의 그룹 소유가 됩니다. `775`는 소유자·그룹 읽기/쓰기/실행, 기타 읽기/실행을 부여합니다.", "source_id": "manual-linux-basic", "difficulty": "hard" }, { "id": "linux-q78", "lesson_id": "linux-fstab", "question_type": "multiple_choice", "question": "`/etc/fstab`에 UUID 기반으로 항목을 추가할 때 UUID를 확인하는 명령은?", "options": [ "blkid", "lsblk -f", "fdisk -l", "mount -l" ], "answer": "blkid", "explanation": "`blkid`는 블록 디바이스의 UUID, TYPE(파일시스템), LABEL을 출력합니다. `lsblk -f`도 유사한 정보를 트리 형태로 보여줍니다. fstab에는 장치명(/dev/sdb1) 대신 UUID를 쓰는 것이 재부팅 시 장치 순서 변경에 안전합니다.", "source_id": "manual-linux-basic", "difficulty": "medium" }, { "id": "linux-q79", "lesson_id": "linux-lvm", "question_type": "multiple_choice", "question": "LVM에서 논리 볼륨의 크기를 20GB로 늘리고 ext4 파일시스템도 함께 확장하는 명령 순서는?", "options": [ "lvextend -L 20G /dev/vg0/lv0 → resize2fs /dev/vg0/lv0", "resize2fs /dev/vg0/lv0 → lvextend -L 20G /dev/vg0/lv0", "vgextend vg0 → resize2fs /dev/vg0/lv0", "lvextend -r -L 20G /dev/vg0/lv0 만으로 완료" ], "answer": "lvextend -r -L 20G /dev/vg0/lv0 만으로 완료", "explanation": "`lvextend -r`(또는 `--resizefs`)은 LV 확장과 파일시스템 확장을 한 번에 처리합니다. 별도로 `resize2fs`를 실행해도 되지만 `-r` 옵션 하나로 통합 가능합니다.", "source_id": "manual-linux-basic", "difficulty": "hard" }, { "id": "linux-q80", "lesson_id": "linux-ssh", "question_type": "multiple_choice", "question": "SSH 서버에서 root 계정의 비밀번호 로그인을 차단하고 키 기반 인증만 허용하려면 `sshd_config`에서 설정할 항목은?", "options": [ "PermitRootLogin prohibit-password", "PermitRootLogin no", "PasswordAuthentication no", "PermitRootLogin prohibit-password 와 PasswordAuthentication no 모두" ], "answer": "PermitRootLogin prohibit-password 와 PasswordAuthentication no 모두", "explanation": "`PermitRootLogin prohibit-password`는 root의 비밀번호 인증만 차단(키 인증은 허용). `PasswordAuthentication no`는 모든 사용자의 비밀번호 인증을 차단합니다. 둘을 함께 적용해야 root 비밀번호 로그인이 완전히 차단됩니다.", "source_id": "manual-linux-basic", "difficulty": "medium" }, { "id": "linux-cmd-1", "lesson_id": "linux-cp-mv-rm", "question_type": "command", "question": "`/etc/hosts` 파일을 권한·소유자·타임스탬프를 보존하며 `/tmp/hosts.bak`으로 복사하는 명령을 입력하세요.", "options": [], "answer": "cp -a /etc/hosts /tmp/hosts.bak", "explanation": "`cp -a`는 `-dR --preserve=all`의 단축으로 속성을 완전히 보존합니다. 단순 `cp`는 타임스탬프와 권한을 보존하지 않습니다.", "source_id": "manual-linux-basic", "difficulty": "medium" }, { "id": "linux-cmd-2", "lesson_id": "linux-grep", "question_type": "command", "question": "`/etc/ssh/sshd_config` 파일에서 주석(#으로 시작하는 줄)을 제외하고 내용을 출력하는 명령을 입력하세요.", "options": [], "answer": "grep -v '^#' /etc/ssh/sshd_config", "explanation": "`-v`는 패턴과 일치하지 않는 줄을 출력(반전), `^#`은 줄의 시작이 #인 줄을 의미합니다.", "source_id": "manual-linux-basic", "difficulty": "medium" }, { "id": "linux-cmd-3", "lesson_id": "linux-find", "question_type": "command", "question": "시스템 전체에서 SUID 비트가 설정된 파일을 찾는 명령을 입력하세요.", "options": [], "answer": "find / -perm -4000 -type f", "explanation": "`-perm -4000`은 SUID 비트(4000)가 설정된 파일을 찾습니다. `-`를 앞에 붙이면 해당 비트가 포함된 파일 모두를 찾습니다.", "source_id": "manual-linux-basic", "difficulty": "hard" }, { "id": "linux-cmd-4", "lesson_id": "linux-tar", "question_type": "command", "question": "`/var/log` 디렉터리를 gzip 압축해 `/tmp/log_backup.tar.gz`로 만드는 명령을 입력하세요.", "options": [], "answer": "tar -czf /tmp/log_backup.tar.gz /var/log", "explanation": "`-c`(create), `-z`(gzip 압축), `-f`(파일 이름 지정). 생성할 아카이브 이름 → 원본 경로 순서로 인수를 씁니다.", "source_id": "manual-linux-basic", "difficulty": "medium" }, { "id": "linux-cmd-5", "lesson_id": "linux-tar", "question_type": "command", "question": "`/tmp/log_backup.tar.gz`의 내용을 현재 디렉터리에 압축 해제하는 명령을 입력하세요.", "options": [], "answer": "tar -xzf /tmp/log_backup.tar.gz", "explanation": "`-x`(extract), `-z`(gzip), `-f`(파일 이름). `-C /경로`를 추가하면 특정 디렉터리에 압축 해제할 수 있습니다.", "source_id": "manual-linux-basic", "difficulty": "easy" }, { "id": "linux-cmd-6", "lesson_id": "linux-chmod", "question_type": "command", "question": "`/srv/app` 디렉터리와 그 하위 모든 파일에 소유자는 rwx, 그룹은 rx, 기타는 아무 권한도 없게 재귀적으로 설정하는 명령을 입력하세요.", "options": [], "answer": "chmod -R 750 /srv/app", "explanation": "`750` = 소유자(7=rwx), 그룹(5=r-x), 기타(0=---). `-R`은 재귀 적용입니다.", "source_id": "manual-linux-basic", "difficulty": "medium" }, { "id": "linux-cmd-7", "lesson_id": "linux-acl", "question_type": "command", "question": "`/project` 디렉터리에 `devteam` 그룹이 읽기·쓰기·실행 권한을 갖도록 ACL을 설정하는 명령을 입력하세요.", "options": [], "answer": "setfacl -m g:devteam:rwx /project", "explanation": "`setfacl -m`(modify) `g:그룹명:권한` 형식으로 그룹 ACL을 설정합니다. 기존 권한은 유지됩니다.", "source_id": "manual-linux-basic", "difficulty": "hard" }, { "id": "linux-cmd-8", "lesson_id": "linux-useradd", "question_type": "command", "question": "홈 디렉터리를 자동 생성하면서 `alice`라는 사용자를 만들고 기본 셸을 `/bin/bash`로 설정하는 명령을 입력하세요.", "options": [], "answer": "useradd -m -s /bin/bash alice", "explanation": "`-m`은 홈 디렉터리 생성, `-s`는 기본 셸 지정입니다. 이 옵션 없이 useradd만 실행하면 홈 디렉터리가 생성되지 않습니다.", "source_id": "ubuntu-user-management", "difficulty": "medium" }, { "id": "linux-cmd-9", "lesson_id": "linux-chage", "question_type": "command", "question": "`bob` 사용자의 비밀번호 만료 정책(최대 사용일, 경고일 등)을 확인하는 명령을 입력하세요.", "options": [], "answer": "chage -l bob", "explanation": "`chage -l`(list)은 사용자의 비밀번호 정책(마지막 변경일, 최대 사용일, 경고일, 계정 만료일)을 보기 좋게 출력합니다.", "source_id": "ubuntu-user-management", "difficulty": "medium" }, { "id": "linux-cmd-10", "lesson_id": "linux-systemctl", "question_type": "command", "question": "`nginx` 서비스가 현재 실행 중인지 확인하는 명령을 입력하세요.", "options": [], "answer": "systemctl status nginx", "explanation": "`systemctl status`는 서비스 상태, 최근 로그, PID, 메모리 사용량을 한눈에 보여줍니다. `is-active nginx`는 active/inactive만 출력합니다.", "source_id": "manual-linux-basic", "difficulty": "easy" }, { "id": "linux-cmd-11", "lesson_id": "linux-systemd-unit", "question_type": "command", "question": "유닛 파일 수정 후 systemd가 변경 사항을 인식하도록 새로고침하는 명령을 입력하세요.", "options": [], "answer": "systemctl daemon-reload", "explanation": "유닛 파일(`/etc/systemd/system/*.service`)을 수정하면 systemd가 자동으로 감지하지 않습니다. `daemon-reload` 후 `restart`해야 변경이 적용됩니다.", "source_id": "manual-linux-systemd", "difficulty": "medium" }, { "id": "linux-cmd-12", "lesson_id": "linux-journalctl", "question_type": "command", "question": "`nginx` 서비스의 로그를 최근 50줄만 출력하는 명령을 입력하세요.", "options": [], "answer": "journalctl -u nginx -n 50", "explanation": "`-u`는 특정 유닛(서비스) 필터, `-n 50`은 최근 50줄 출력입니다. `-f`를 추가하면 실시간 스트리밍됩니다.", "source_id": "manual-linux-basic", "difficulty": "medium" }, { "id": "linux-cmd-13", "lesson_id": "linux-cron", "question_type": "command", "question": "현재 사용자의 crontab을 편집하는 명령을 입력하세요.", "options": [], "answer": "crontab -e", "explanation": "`crontab -e`는 기본 편집기로 현재 사용자의 crontab을 엽니다. `-l`은 목록 확인, `-r`은 삭제입니다.", "source_id": "manual-linux-basic", "difficulty": "easy" }, { "id": "linux-cmd-14", "lesson_id": "linux-df-du-mount", "question_type": "command", "question": "현재 마운트된 파일시스템의 디스크 사용량을 사람이 읽기 쉬운 단위(GB, MB)로 출력하는 명령을 입력하세요.", "options": [], "answer": "df -h", "explanation": "`df -h`는 `-h`(human-readable) 옵션으로 GB, MB 단위로 용량을 표시합니다. `-T`를 추가하면 파일시스템 유형도 함께 출력됩니다.", "source_id": "manual-linux-basic", "difficulty": "easy" }, { "id": "linux-cmd-15", "lesson_id": "linux-lvm", "question_type": "command", "question": "시스템의 모든 논리 볼륨(LV) 목록을 확인하는 명령을 입력하세요.", "options": [], "answer": "lvs", "explanation": "`lvs`(LV summary)는 간결한 LV 목록을 출력합니다. `lvdisplay`는 더 자세한 정보를, `lvscan`은 모든 LV와 활성 상태를 보여줍니다.", "source_id": "manual-linux-basic", "difficulty": "medium" }, { "id": "linux-cmd-16", "lesson_id": "linux-fstab", "question_type": "command", "question": "`/etc/fstab`에 등록된 모든 파일시스템을 마운트하는 명령을 입력하세요.", "options": [], "answer": "mount -a", "explanation": "`mount -a`는 fstab의 noauto 옵션이 없는 모든 항목을 마운트합니다. fstab 수정 후 재부팅 없이 테스트할 때 사용합니다.", "source_id": "manual-linux-basic", "difficulty": "medium" }, { "id": "linux-cmd-17", "lesson_id": "linux-ssh-key", "question_type": "command", "question": "ED25519 알고리즘으로 SSH 키 쌍을 생성하는 명령을 입력하세요.", "options": [], "answer": "ssh-keygen -t ed25519", "explanation": "ED25519는 RSA 4096보다 짧고 강력한 알고리즘입니다. 생성된 공개 키(`~/.ssh/id_ed25519.pub`)를 서버의 `authorized_keys`에 등록합니다.", "source_id": "manual-linux-basic", "difficulty": "medium" }, { "id": "linux-cmd-18", "lesson_id": "linux-sed", "question_type": "command", "question": "`/etc/hosts` 파일에서 `oldhost`를 `newhost`로 모두 바꿔 파일을 직접 수정하는 명령을 입력하세요.", "options": [], "answer": "sed -i 's/oldhost/newhost/g' /etc/hosts", "explanation": "`-i`는 파일을 직접 수정(in-place), `s/패턴/교체/g`에서 `g`는 줄 내 모든 일치 항목을 교체합니다. `-i.bak`으로 백업도 만들 수 있습니다.", "source_id": "manual-linux-basic", "difficulty": "hard" }, { "id": "linux-cmd-19", "lesson_id": "linux-text-pipeline", "question_type": "command", "question": "`/var/log/auth.log`에서 `Failed` 문자열이 포함된 줄만 뽑아 IP 주소 필드(첫 번째 공백 기준 필드 11)별 시도 횟수를 내림차순으로 출력하는 파이프라인을 입력하세요.", "options": [], "answer": "grep 'Failed' /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -rn", "explanation": "grep→awk로 필드 추출→sort로 정렬→uniq -c로 중복 카운트→sort -rn으로 내림차순. 브루트포스 공격 IP를 파악하는 실전 패턴입니다.", "source_id": "manual-linux-basic", "difficulty": "hard" }, { "id": "linux-cmd-20", "lesson_id": "linux-docker-basics", "question_type": "command", "question": "실행 중인 `webserver` 컨테이너 내부에서 `/bin/bash` 셸을 인터랙티브 터미널로 실행하는 명령을 입력하세요.", "options": [], "answer": "docker exec -it webserver /bin/bash", "explanation": "`docker exec -it`는 실행 중인 컨테이너 내부에서 명령을 실행합니다. `-i`(stdin 유지), `-t`(터미널 할당). 컨테이너 안에서 디버깅할 때 필수 패턴입니다.", "source_id": "manual-linux-docker", "difficulty": "medium" }, { "id": "linux-cmd-21", "lesson_id": "linux-mkfs-fsck", "question_type": "command", "question": "`/dev/sdb1` 파티션의 UUID를 확인하는 명령을 입력하세요.", "options": [], "answer": "blkid /dev/sdb1", "explanation": "`blkid`는 블록 디바이스의 UUID, 파일시스템 유형(TYPE), 레이블을 출력합니다. fstab에 UUID 기반으로 등록할 때 이 명령으로 값을 확인합니다.", "source_id": "manual-linux-storage", "difficulty": "medium" }, { "id": "linux-cmd-22", "lesson_id": "linux-at", "question_type": "command", "question": "1시간 후에 `/usr/local/bin/cleanup.sh`를 한 번 실행하도록 예약하는 명령을 입력하세요.", "options": [], "answer": "echo '/usr/local/bin/cleanup.sh' | at now + 1 hour", "explanation": "`echo '명령' | at 시간` 형식으로 일회성 작업을 예약합니다. 예약 목록은 `atq`, 취소는 `atrm 번호`로 관리합니다.", "source_id": "manual-linux-basic", "difficulty": "hard" } ]