복구가 필요한 다운로드 판단하기

ShellBeginner
지금 연습하기

소개

Field Notes는 지역 주말 행사를 준비하고 있습니다. 자료 팩에는 PDF 안내서, 배포 자료, 비어 있어도 되는 선택적 감사 명단 파일이 포함됩니다. 파일 이름과 그럴듯한 크기만으로 다운로드가 완전하다고 할 수는 없습니다. 무언가를 가져오기 전에 어떤 파일에 조치가 필요한지 운영팀에 정확히 알려 주는 목록을 만듭니다.

Shell for Beginners에서 다루는 기본 Bash 인수, 조건문, 반복문을 알고 있다고 가정합니다. 이 실습에서는 SHA256, 전체 줄 읽기, 사용할 분류 방식을 설명합니다. 도구와 직접 만든 합성 자료는 준비되어 있습니다. Workspace와 Download Desk는 하나의 컨테이너를 공유하며, 이 실습은 독립적으로 시작합니다. 예상 시간에는 읽기와 일반적인 오타 수정이 포함됩니다.

근거 있는 목록 만들기

이 단계에서는 신뢰할 수 있는 확인 목록을 실제 로컬 팩의 목록으로 바꿉니다. 팩 파일을 복구하거나 다시 쓰지는 않습니다.

먼저 유용한 파일 확인하기

UTF-8 텍스트를 사용할 수 있도록 준비된 Workspace에서 시작합니다. 작업 디렉터리는 /home/labex/project/download-desk입니다. pwd는 현재 디렉터리를 표시합니다. 상대 경로를 찾지 못하면 ls로 확인하고, 다음의 완전한 cd 명령으로 이 위치로 돌아옵니다.

cd /home/labex/project/download-desk
ls pack

Download Desk로 전환합니다. Welcome guide.pdf 옆의 Open file을 선택합니다. 새 브라우저 페이지에는 행사 일정과 동쪽 입구의 집합 장소가 보여야 합니다. 필요하면 PDF 리더의 확대/축소 기능을 사용합니다. PDF는 고정된 페이지이며, 모바일 화면에 맞춰 텍스트가 재배치되는 레이아웃이 아닙니다. Download Desk 페이지로 돌아가 파일 옆의 Download를 선택하여 동일한 로컬 바이트를 저장합니다. 그런 다음 Workspace로 돌아갑니다.

실제 로컬 자료 링크를 보여 주는 Download Desk

Welcome guide.pdf 옆의 Open file 또는 Download를 사용합니다.

이 리더는 pack에 실제로 있는 파일만 제공합니다. 누락 파일을 원본 제공처에서 보충할 수 없습니다. 텍스트 자료는 텍스트로, 선택적 빈 파일은 빈 페이지로 보일 수 있습니다. 이 관찰만으로 내용이 올바르다고 증명할 수는 없습니다.

독립적인 기준 사용하기

운영팀은 쓰기 가능한 팩과 별도로 /opt/labex/download-pack-state/expected.sha256을 제공했습니다. SHA256 해시는 파일 바이트의 64자 지문입니다. 독립적이고 신뢰할 수 있는 값과 비교하면 파일 크기가 그대로인 손상을 포함하여 바이트 차이를 찾을 수 있습니다. 게시자의 신원을 확인하는 것은 아닙니다. 공격자가 파일과 체크섬을 모두 제공했다면, 둘이 일치해도 게시자를 신뢰할 근거가 되지 않습니다. 확인할 파일에서 기준을 새로 만들지 마세요.

cat은 파일을 바꾸지 않고 표시합니다.

cat /opt/labex/download-pack-state/expected.sha256

각 줄은 소문자 64자리 16진수 해시, 공백 두 개, 전체 파일 이름으로 구성됩니다. 이 과정은 정확히 이 형식으로 제공된 읽기 가능하고 비어 있지 않으며 마지막에 줄바꿈이 있는 매니페스트를 사용합니다. 이름은 하위 경로가 없는 인쇄 가능한 ASCII이며 공백을 포함할 수 있습니다. 슬래시, 역슬래시, CR, LF, 탭 및 .과 ..이라는 이름은 범위 밖입니다. 팩과 해당 디렉터리 경로의 모든 디렉터리는 실제 디렉터리이며, 나열된 항목은 일반 로컬 파일이거나 없어야 합니다. 링크된 파일, 예상 파일 위치의 하위 디렉터리, 임의의 이스케이프된 체크섬 형식은 지원하지 않습니다. 이 진단 실습에서는 원래 팩 파일과 notes.txt를 모두 그대로 둡니다.

sha256sum은 해시와 파일 이름을 출력합니다. 큰따옴표는 공백이 있는 이름을 하나의 인수로 유지합니다. --는 명령 옵션의 끝을 나타냅니다. 디렉터리 접두사도 -로 시작하는 기본 이름이 옵션으로 해석되는 것을 막습니다.

sha256sum -- "pack/Workshop card.txt"

이 해시를 기준 줄과 비교합니다. 두 값은 다릅니다. 손상된 파일의 바이트 수는 올바른 배포 자료와 같으므로 크기로는 문제를 찾을 수 없었습니다.

sha256sum --check는 매니페스트를 읽고 현재 디렉터리를 기준으로 해당 경로를 확인합니다. 괄호는 서브셸에서 명령을 실행합니다. 그 안의 cd는 바깥 터미널의 디렉터리를 바꾸지 않습니다.

(cd pack && sha256sum --check /opt/labex/download-pack-state/expected.sha256)

여기서 &&는 pack으로 이동한 경우에만 검사를 실행합니다. Welcome guide.pdf: OK, Workshop card.txt: FAILED, Map notes.txt: FAILED open or read, Optional credits.txt: OK 및 경고가 보여야 합니다. 누락 파일과 잘못된 바이트 때문에 의도적으로 실패하는 명령입니다. $?는 직전 명령의 실제 종료 상태를 담습니다. 다른 명령이 값을 덮어쓰기 전에 즉시 읽으세요. printf는 값을 형식에 맞게 출력하고 \n은 줄을 끝냅니다.

printf 'Check exit: %s\n' "$?"

예상 결과는 Check exit: 1입니다. 0바이트 감사 명단 파일은 해시가 일치하므로 유효합니다. “비어 있지 않음”은 각 자료가 아니라 매니페스트의 요건입니다. 한 줄의 OK로 팩 전체가 올바르다고 판단할 수는 없습니다.

줄을 읽을 때 이름 보존하기

운영팀은 매니페스트 순서대로 각 줄에 상태와 전체 파일 이름을 표시하는 간단한 목록이 필요합니다. 매니페스트를 $1, 팩 디렉터리를 $2로 받는 inventory.sh를 만듭니다. 이 프로그램은 인수와 설치된 명령을 사용하는 독립 프로그램이며 옆에 별도 보조 파일이 필요하지 않습니다.

작성 전에 사용할 셸 구문을 살펴봅니다.

  • while IFS= read -r line은 반복할 때마다 한 줄 전체를 읽습니다. 빈 IFS는 공백 제거를 막고, -r은 역슬래시 해석을 막습니다. done < "$manifest"는 터미널 입력을 요청하는 대신 매니페스트를 반복문으로 리디렉션합니다.
  • ${line:0:64}는 문자 위치 0부터 63까지의 해시를 추출합니다. ${line:66}은 구분 공백 두 개 뒤의 내용을 모두 추출합니다. 파일 이름을 단어로 나누지 않습니다.
  • [ -f "$target" ]은 지원 대상이 일반 파일인지 확인합니다. 누락 항목은 체크섬 명령을 실행하기 전에 분류합니다.
  • actual=$(sha256sum -- "$target")은 명령 출력을 받아옵니다. ${actual%% *}는 공백과 그 뒤의 임의 텍스트에 일치하는 가장 긴 접미부를 제거하여 해시만 남깁니다. 위에서 설명한 제한된 이름 형식에서 안전합니다.
  • printf '%s\t%s\n'은 두 값 사이에 탭을 넣고 마지막에 줄바꿈을 출력합니다. 따옴표는 각각의 전체 이름을 하나의 인수로 보존합니다.

다음 히어 도큐먼트는 텍스트를 그대로 스크립트에 저장합니다. cat > inventory.sh는 이 스크립트 파일을 교체합니다. <<'BASH'는 BASH만 있는 줄에서 끝납니다. 구분자의 따옴표는 저장하는 동안 현재 셸이 스크립트 변수를 확장하지 못하게 합니다. 첫 줄은 Bash를 지정하며, 여기서는 명시적으로 bash로 파일을 실행합니다.

cat > inventory.sh <<'BASH'
#!/usr/bin/env bash
manifest=$1
pack=$2
while IFS= read -r line; do
    expected=${line:0:64}
    name=${line:66}
    target=$pack/$name
    status=MISSING
    if [ -f "$target" ]; then
        actual=$(sha256sum -- "$target")
        actual=${actual%% *}
        status=MISMATCH
        if [ "$actual" = "$expected" ]; then
            status=MATCH
        fi
    fi
    printf '%s\t%s\n' "$status" "$name"
done < "$manifest"
BASH

제공된 기준과 로컬 팩을 인수로 스크립트를 실행합니다. >는 표준 출력을 inventory.tsv로 리디렉션하며 실행할 때마다 보고서를 교체합니다. TSV는 탭으로 구분된 값을 뜻합니다. 이 보고서는 운영팀의 진단 결과이며 자료를 복구하지 않습니다.

bash inventory.sh /opt/labex/download-pack-state/expected.sha256 pack > inventory.tsv
cat inventory.tsv

각 상태와 파일 이름 사이에 탭 하나가 있는 다음 줄들을 예상합니다.

MATCH Welcome guide.pdf
MISMATCH Workshop card.txt
MISSING Map notes.txt
MATCH Optional credits.txt

보고서에 MISSING이 있어도 스크립트는 종료 상태 0으로 끝날 수 있습니다. 목적은 팩이 완전하다고 주장하는 것이 아니라 분류하는 것이기 때문입니다. 보고서의 정확성은 실제 파일 및 신뢰할 수 있는 기준과의 관계에서 나옵니다. 검사는 다른 이름과 빈 파일이 있는 다른 팩에서도 스크립트를 시험합니다. 이 반복문 표현 자체를 요구하지는 않습니다.

스크립트 줄을 잘못 입력했다면 히어 도큐먼트 전체를 반복하여 inventory.sh만 교체하고 보고서를 다시 만듭니다. 실수로 pack 안에서 작업했다면 위의 절대 경로 cd로 돌아옵니다. pack, 신뢰할 수 있는 기준, notes.txt는 그대로 둡니다. 목록 프로그램은 팩을 읽기만 하므로 다시 실행해도 같은 보고서를 내야 합니다. 다음 실습에서는 이 분류를 토대로 다운로드할 대상을 결정합니다.

요약

실제 자료를 열고, 독립적인 SHA256 기준과 팩을 비교하고, 전체 줄을 보존하는 Bash 목록 프로그램을 만들었습니다. 원본 팩을 바꾸지 않고 누락 파일, 잘못된 바이트, 유효한 빈 파일을 구분했습니다. 이 목록은 이후 각 복구의 근거가 됩니다.