본문 바로가기
빌드노트 검색

빌드노트

tar에 -C를 줬는데 report.txt를 다른 곳에서 찾는 이유

GNU tar의 -C는 뒤에 오는 파일 인자에 적용된다. 파일 앞뒤의 옵션 순서와 연속 상대경로 b·../b를 비교하고, 종료 코드·멤버 이름·실제 내용으로 읽은 원본을 확인한다. 같은 이름으로 저장되는 두 파일은 공통 부모의 하위 경로로 구별할 수 있다.

GNU tar에 -C를 줬는데도 report.txt를 찾지 못한다면 파일 이름과 옵션의 순서부터 본다. -C 디렉터리는 그 뒤에 오는 파일 인자의 기준을 바꾼다. report.txt -C 디렉터리는 앞의 파일에 적용되지 않는다. 원본이 있는 곳을 지정하려면 -C 디렉터리 report.txt 순서로 옮긴다. GNU tar의 위치 의존 옵션 설명 (새 탭에서 열림)

-C를 파일 앞으로 옮겨 비교한다

비교는 WSL Ubuntu 24.04의 GNU tar 1.35에서 실행했다. tar --version의 첫 줄이 tar (GNU tar) 1.35인 WSL Bash를 사용했고, 추가 TAR_OPTIONS 없이 LC_ALL=C로 오류를 읽었다. 아래 실패 뒤에도 계속 확인하려면 set -e를 켜지 않은 셸이 필요하다.

따라 확인할 때는 새 실습 폴더에 나란한 a, b 폴더와 빈 out 폴더를 준비한다. a/report.txt에는 from-A, b/report.txt에는 from-B를 각각 한 줄씩 넣는다. 두 입력 폴더에는 이 파일만 두고, 공통 부모에는 report.txt를 두지 않는다. 그 공통 부모를 현재 위치로 삼아 아래 명령을 같은 셸에서 순서대로 실행한다. 재실행할 때도 새 실습 폴더를 써서 출력 아카이브가 기존 파일과 겹치지 않게 한다.

다음 비교에서 바꾸는 것은 -C의 위치다. 각 echo는 바로 앞 생성 명령의 종료 코드를 확인한다.

lab=$(pwd -P)
tar -cf "$lab/out/late.tar" report.txt -C "$lab/a"
echo "$?"
tar -cf "$lab/out/one.tar" -C "$lab/a" report.txt
echo "$?"
tar -tf "$lab/out/one.tar"
tar -xOf "$lab/out/one.tar" report.txt

실패한 첫 생성은 종료 코드 2와 stderr의 report.txt: Cannot stat: No such file or directory, 마지막 -C가 has no effect라는 안내를 남겼다. 앞의 파일은 시작 위치에서 찾고, 뒤의 -C에는 적용할 입력이 없었기 때문이다. 고친 생성은 0이었으며 목록은 report.txt, 내용은 from-A였다. 고친 뒤 생성·조회·추출의 stderr는 비었고 종료 코드는 모두 0이었다.

-cf는 생성, -tf는 목록 조회다. -xOf는 파일을 디스크에 풀지 않고 내용을 표준 출력으로 읽으므로, 이 예제에서는 from-A가 들어갔는지 바로 대조할 수 있다. GNU tar의 표준 출력 추출 설명 (새 탭에서 열림)

시작 위치에 같은 이름의 파일이 있는 조건도 따로 비교했다. b를 시작 위치로 삼고 새 아카이브에 첫 명령과 같은 순서를 적용하자 from-B가 들어갔다. 마지막 -C 무효 안내와 생성 종료 코드 2는 그대로였다. 아카이브가 생기고 목록이 읽혀도 생성 성공으로 판단하면 안 된다.

한편 b에서 입력을 report.txt -C "$lab/a" report.txt로 주면 생성은 0이었고 B 다음 A가 들어갔다. 파일 뒤에 등장한 -C라도 다음 파일에는 적용된다. 이미 앞에 적은 파일의 기준을 소급해서 바꾸지 않는다는 뜻이다.

-C를 두 번 쓰면 기준도 이어서 바뀐다

같은 두 원본을 넣을 때 각 입력 앞에 절대경로를 지정하면 읽을 위치가 분명하다. 셸의 현재 위치는 계속 공통 부모인 $lab이다.

tar -cf "$lab/out/two-absolute.tar" \
  -C "$lab/a" report.txt -C "$lab/b" report.txt
echo "$?"
tar -tf "$lab/out/two-absolute.tar"
tar -xOf "$lab/out/two-absolute.tar" report.txt

생성은 0이고 stderr는 비었다. 목록에는 report.txt가 두 줄, 내용 출력에는 from-A 다음 from-B가 나왔다. 같은 이름을 가진 멤버를 표준 출력으로 추출하면 내용이 이어서 나오므로, 이 두 줄짜리 예제에서는 원본을 구별할 수 있다. 일반 파일의 경계까지 표시해 주는 출력은 아니다. 두 멤버를 각각 빈 폴더에 따로 추출한 비교에서도 A와 B를 확인했다.

-C의 경로가 멤버 이름에 자동으로 붙지는 않는다. 이름으로도 구별해 보관하려면 공통 부모에서 하위 경로를 넘긴다. tar -cf "$lab/out/with-dirs.tar" -C "$lab" a/report.txt b/report.txt로 만든 결과는 멤버 이름이 a/report.txt, b/report.txt이고 내용도 각각 A와 B였다. GNU tar의 디렉터리 변경과 멤버 이름 설명 (새 탭에서 열림)

상대경로는 앞선 -C로 바뀐 위치에서 계산해야 한다. 다음 비교는 두 번째 목적지를 b에서 ../b로 고친다.

tar -cf "$lab/out/two-relative-wrong.tar" -C a report.txt -C b report.txt
echo "$?"
tar -cf "$lab/out/two-relative-chain.tar" -C a report.txt -C ../b report.txt
echo "$?"

첫 생성은 2와 tar: b: Cannot open: No such file or directory를 남겼다. 두 번째 -C b는 $lab/b가 아니라 $lab/a/b로 가려 하기 때문이다. ../b로 고친 생성은 0, 빈 stderr였고 목록의 두 report.txt와 각각 추출한 A·B 내용도 절대경로 비교와 같았다. tar 내부의 디렉터리 변경은 부모 Bash의 현재 위치를 바꾸지 않는다. GNU tar의 연속 상대경로 규칙 (새 탭에서 열림)

실패한 상대경로 생성물은 이번 작은 입력에서는 목록 조회도 2였으며 This does not look like a tar archive가 나왔다. 실패하면 일부 파일이 반드시 남는다고 가정하지 않는다. 자신의 명령에서도 각 입력에 적용되는 -C를 먼저 계산하고, 생성 종료 코드·stderr를 확인한 다음 멤버 이름과 내용을 대조한다.

직접 확인한 범위는 GNU tar 1.35의 일반 파일과 압축하지 않은 새 아카이브다. bsdtar 등 BSD 계열 tar, -T 파일 목록, 링크, 권한·소유권 복원은 비교하지 않았다.

← 전체 글 보기