소개
DAYMARK 는 작은 카페입니다. 마감 시 팀은 장부에 사용할 매출 CSV 를 다운로드합니다. 계산이 실패해도 마지막 완전한 파일을 교체해서는 안 됩니다. 먼저 합계를 이해하고 짧은 Bash 게시 래퍼를 완성합니다. 계산 프로그램은 제공됩니다.
기본 터미널 사용 능력이면 충분합니다. 명령과 셸 문법은 사용 전에 설명합니다. 포트 8081 의 실제 웹사이트 Daymark에서 시작하고, 명령은 /srv/daymark-sales에 준비된 Workstation에서 실행합니다. 데이터는 가상이며 설치나 외부 계정은 필요하지 않습니다.
마감 합계 이해하고 계산하기
이 단계에서는 카페의 원본 주문을 실제 후보 내보내기와 비교합니다. Daymark에서 View source records ↗를 엽니다. 원본 네 행은 단가 300 센트인 Espresso 6 개, 250 센트인 Tea 3 개, 450 센트인 Cake 2 개로, 총 11 개와 3450 센트입니다. 센트는 통화 단위의 100 분의 1 이며 정수 센트는 반올림의 모호함을 피합니다. 같은 품목의 반복 행은 합쳐야 합니다.

Reports와 Download latest CSV ↓를 열면 실제 CSV 파일이 저장됩니다. CSV 는 쉼표로 구분한 값이며 첫 행은 열 이름입니다. 초기 파일은 TOTAL,1,100이 있는 이전 마감 보고서입니다. 완전한 대체 파일이 생길 때까지 계속 사용할 수 있어야 합니다. DAYMARK로 홈에 돌아갑니다.
Workstation으로 전환합니다. pwd는 작업 디렉터리, ls는 파일 목록, cat은 텍스트 파일을 출력합니다. 상대 경로는 현재 디렉터리에서 해석됩니다.
pwd
/srv/daymark-sales가 나와야 합니다.
ls
cat orders.csv
행이 웹사이트와 일치합니다. python3는 제공된 계산기를 실행하며 절대 경로이므로 현재 디렉터리에 영향을 받지 않습니다. >는 표준 출력을 파일로 리디렉션하고 프로그램 실행 전에 그 파일을 교체합니다. 게시된 보고서가 아닌 별도 후보 파일을 사용하세요.
/usr/bin/python3 /opt/labex/d10/summarize.py orders.csv > candidate.csv
cat candidate.csv
item,quantity,value_cents
Cake,2,900
Espresso,6,1800
Tea,3,750
TOTAL,11,3450
원본은 단가를 사용하고 보고서는 합산 수량과 총가치를 사용합니다. 종료 상태 0 은 성공, 0 이외 값은 실패입니다. $?는 직전 명령의 상태로 확장되므로 확인하려는 명령 바로 다음에 읽어야 합니다. echo는 텍스트를 출력합니다.
/usr/bin/python3 /opt/labex/d10/summarize.py fixtures/broken.csv > rejected.csv
echo $?
Export failed: ...와 1이 나와야 하며 의도된 실패입니다. 계산이 실패했어도 cat rejected.csv는 헤더를 보여 줍니다. 부분 출력은 유효한 보고서가 아닙니다. 별도 후보만 작성했으므로 기존 다운로드는 여전히 TOTAL,1,100입니다. 경로가 잘못되면 pwd와 ls로 살펴보고 cd /srv/daymark-sales로 돌아가 후보 명령을 다시 실행합니다. cd는 디렉터리를 바꿉니다. 원본 주문과 기존 보고서를 보존하세요.
성공한 뒤에만 게시하기
이 단계에서는 안전하지 않은 래퍼를 교체하고 보존과 새 데이터 복구를 모두 확인합니다. Workstation에서 시작합니다. 래퍼는 입력 CSV 와 게시 경로라는 두 인수를 받습니다. 내용을 읽어 보세요.
cat publish.sh
직접 쓰는 >는 실패하는 계산이 끝나기 전에 게시 파일을 잘라낼 수 있습니다. 대신 대상 옆에 임시 파일을 만들고 성공적으로 쓴 다음 이름을 바꿉니다. 같은 파일시스템에서 이름 변경은 보이는 파일 이름을 원자적으로 교체하여 독자가 완전한 이전 바이트 또는 완전한 새 바이트를 보게 합니다. 이는 데이터베이스 트랜잭션이나 디스크 손실 방지를 제공하지 않습니다.
Bash 가 작은 래퍼를 실행합니다. set -e는 일반 명령 실패 시 멈추고 -u는 설정되지 않은 변수를 거부합니다. $1과 $2는 두 인수입니다. name=value는 = 주위에 공백 없이 셸 변수에 대입하며 $(command)는 명령 출력을 캡처합니다. 따옴표는 경로의 공백을 보존합니다. mktemp는 XXXXXX 접미사로 고유한 파일을 만듭니다. trap ... EXIT는 성공과 실패 모두에서 남은 임시 데이터를 삭제합니다. chmod 644는 소유자에게 쓰기를, 모두에게 읽기를 허용합니다. mv -fT는 정확한 대상 파일 이름을 교체하고 -T는 대상이 디렉터리이면 그 안으로 옮기지 않고 거부합니다. printf는 게시 상세를, id -u는 실제 숫자 사용자 ID 를 출력하며 sha256sum은 파일 바이트를 식별합니다.
cat > publish.sh는 자신의 래퍼만 교체합니다. 따옴표로 감싼 SH는 here-document 를 시작합니다. 마지막 SH가 독립된 행이 되도록 끝까지 붙여넣으세요. 따옴표가 달러 기호를 문자 그대로 보존합니다.
cat > publish.sh <<'SH'
#!/bin/bash
set -eu
input=$1
output=$2
tmp=$(mktemp "${output}.XXXXXX")
trap 'rm -f "$tmp"' EXIT
/usr/bin/python3 /opt/labex/d10/summarize.py "$input" > "$tmp"
chmod 644 "$tmp"
mv -fT "$tmp" "$output"
printf 'Published %s uid=%s cwd=%s sha256=' "$output" "$(id -u)" "$PWD"
sha256sum "$output"
SH
준비된 daymark-report 계정이 reports/를 소유합니다. 이 계정은 보고서를 쓰고 웹사이트는 읽기만 합니다. sudo -u는 해당 계정으로 실행합니다. /bin/bash는 절대 경로이며 래퍼를 Bash 에 명시적으로 전달하면 래퍼 자체의 실행 권한은 필요하지 않습니다.
sudo -u daymark-report /bin/bash /srv/daymark-sales/publish.sh orders.csv /srv/daymark-sales/reports/sales.csv
cat reports/sales.csv
완전한 TOTAL,11,3450 보고서가 나와야 합니다. cp는 파일을 복사합니다. 이 실습의 orders.csv만 덮어쓰고 원래 fixture 는 보존하세요. 이어서 의도적으로 잘못된 입력을 전달합니다.
cp fixtures/broken.csv orders.csv
sudo -u daymark-report /bin/bash /srv/daymark-sales/publish.sh orders.csv /srv/daymark-sales/reports/sales.csv
echo $?
의도된 실패와 1이 나와야 합니다. Daymark로 전환하여 Reports를 새로 고치고 다시 다운로드해 TOTAL,11,3450이 유지되는지 확인합니다. 실패한 시도는 헤더만 게시하거나 이전 파일을 삭제해서는 안 됩니다.
Workstation으로 돌아갑니다. Tea 가 두 개 추가된 새 유효 마감 데이터로 복구합니다. 예전 보고서를 영원히 두지 말고 13 개와 3950 센트를 만들어야 합니다.
cp fixtures/next.csv orders.csv
sudo -u daymark-report /bin/bash /srv/daymark-sales/publish.sh orders.csv /srv/daymark-sales/reports/sales.csv
cat reports/sales.csv
Tea,5,1250과 TOTAL,13,3950이 나와야 합니다. Daymark에서 Records 와 Reports 를 새로 고치고 다시 다운로드합니다. 원본과 보고서가 일치합니다. 권한이 거부되면 정확한 출력 경로를 확인하고 sudo -u daymark-report 명령을 반복하며 모두에게 쓰기 권한을 주지 마세요. 래퍼에 오타가 있으면 완전한 here-document 로 교체하고 재시도합니다. 임시 파일은 출력 옆에 생성되므로 마지막 이름 변경이 같은 파일시스템에 머뭅니다.
요약
완전한 CSV 게시, 의미 있는 실패 상태와 복구를 연습했습니다. 예약 보고서는 실제 실행 신원, 트리거, 업무 합계가 일치해야 유용합니다. 단일 instance 에서 가상 데이터와 짧은 연습 일정을 사용하는 실습이며 완전한 운영 보고서 플랫폼은 아닙니다.


