macOS에서 tar --wildcards가 Option is not supported 오류를 낼 때: 옵션을 빼면 되는 이유와 오류를 버렸을 때 아무것도 안 풀리는 경우, 패턴이 맞는 범위까지 직접 시험한 결과When tar --wildcards fails with Option is not supported on macOS: why dropping the option works, what happens when the error is discarded and nothing is extracted, and how far the patterns match, tested directly
리눅스식 tar --wildcards 줄을 맥에서 돌려 오류를 만났거나, 오류를 숨긴 스크립트가 아무것도 풀지 않고 지나간 독자가 맥의 tar 에서 같은 일을 하는 방법과 결과가 갈리는 자리를 알게 돕는다.
이 맥(26.6.2)의 bsdtar 3.5.3 는 --wildcards 를 포함한 여섯 개의 GNU 패턴 옵션을 종료 코드 1로 거부한다. 옵션을 빼고 패턴을 따옴표로 막으면 같은 줄이 풀리지만, 이 맥의 패턴은 별표가 슬래시를 넘어 깊은 폴더의 파일까지 맞고, 대소문자를 구분하며, 이름에 대괄호가 든 멤버는 정확한 이름으로 부르면 못 찾는다. 오류를 버리면 풀린 파일 0개에 종료 코드 0으로 지나갈 수 있다.
스크립트에서 tar 에 --wildcards 를 붙인 줄을 찾아 옵션을 빼고 패턴이 따옴표로 막혀 있는지 확인하라. 그 줄의 오류를 2>/dev/null 이나 || true 로 덮은 곳이 있다면 풀린 파일 수를 세는 점검을 붙여라.
목차
한 줄 요약: 맥의 tar 는 시험한 GNU 패턴 옵션 여섯 개를 종료 코드 1로 거부하므로 –wildcards 를 빼고 패턴을 따옴표로 막아 쓰되, 별표가 슬래시를 넘고 대괄호 이름은 이스케이프하며 GNU 와는 ./ 접두어와 종료 코드가 다른 점을 확인한다.
리눅스에서 tar -xf app.tar --wildcards '*.txt' 로 아카이브 안의 .txt 만 풀던 줄을 맥 터미널에서 돌리면 아무것도 풀리지 않고 오류 문구만 남는다. 이 글은 맥의 tar 가 무엇을 거부하는지, 오류를 버린 스크립트가 어떤 상태로 다음 줄에 가는지, 옵션을 빼면 같은 일이 되는지, 그리고 옵션 없이 쓰는 패턴이 이 맥에서 정확히 어디까지 맞는지를 직접 돌려 보인다.
tar: Option --wildcards is not supported
Usage:
List: tar -tf <archive-filename>
Extract: tar -xf <archive-filename>
Create: tar -cf <archive-filename> [filenames...]
Help: tar --help
확인한 환경은 macOS 26.6.2 arm64 의 /usr/bin/tar (bsdtar 3.5.3 - libarchive 3.7.4), bash 3.2.57, zsh 5.9, LC_ALL=C 이고 날짜는 2026-11-04 이다. 시험 스크립트 여섯 개를 두 번씩 돌렸고 두 번째 출력은 첫 번째와 글자까지 같았다. 이 맥에는 GNU tar 가 없어서 gnu.org 의 tar 1.35 소스를 내려받아 이 맥에서 직접 빌드해 비교에 썼다. 리눅스 배포판의 tar 가 아니라 이 맥에서 빌드한 GNU tar 1.35 이다. 읽은 설명서 페이지는 1.35.90 판이다.
용어 몇 개. 종료 코드는 명령이 끝나며 남기는 숫자로 0이 정상이다. GNU tar 는 많은 리눅스 배포판의 tar 이고, 맥의 tar 는 BSD 계열의 bsdtar(libarchive)라 이름이 같아도 옵션이 다르다. 멤버는 아카이브 안에 든 파일 하나하나의 이름이다. 패턴은 * 나 ? 가 들어간 이름 묶음(글롭)이고, 셸이 파일 이름으로 먼저 풀어 버리지 않게 따옴표로 감싸서 쓴다.
맥의 tar 가 거부하는 패턴 옵션
폴더 src 에 a.txt, b.log, c.txt 를 넣어 만든 아카이브에서 tar -tf x.tar 옵션 'src/*.txt' 의 옵션만 바꿔 가며 쟀다. --wildcards, --no-wildcards, --wildcards-match-slash, --no-wildcards-match-slash, --anchored, --no-anchored, 여섯 개 모두 종료 코드 1이었고 오류는 tar: Option --wildcards is not supported 처럼 옵션 이름을 그대로 보여 줬다.
같은 줄에서 옵션만 빼면 종료 코드 0으로 src/a.txt 와 src/c.txt 가 나왔다. 맥의 man tar 도 목록·추출은 tar {-t | -x} [options] [patterns] 형태로만 적고, 패턴은 “tcsh(1) 에 적힌 셸 방식 글롭”이라고 설명한다. 맥의 tar 는 따로 켜지 않아도 패턴을 글롭으로 읽는다는 뜻이고, 그래서 옵션을 붙일 자리가 없다.
2024년 4월에 올라온 한 공개 스크립트(Iris 와 std++ 릴리스용 gist)에도 같은 사정이 주석으로 적혀 있다. “if tar is GNU tar, we need –wildcards” 와 “BSD tar interprets patterns with wildcards by default and has no such option” 두 줄이고, 코드는 tar --version 에 “GNU tar” 가 보일 때만 --wildcards 를 붙인다.
오류를 버리면 풀린 파일 0개로 지나간다
옵션 오류가 시끄러워 2>/dev/null 을 붙인 스크립트를 쟀다. 빈 폴더에서 tar -xf ../x.tar --wildcards 'src/*.txt' 2>/dev/null 은 종료 코드 1에 풀린 파일이 0개였다. 옵션만 뺀 같은 줄은 종료 코드 0에 ./src/a.txt 와 ./src/c.txt 두 개를 풀었다.
set -e를 켠 bash 스크립트에서는 이 줄에서 스크립트가 종료 코드 1로 멈췄고 다음echo는 실행되지 않았다. 이 경우 오류를 버려도 멈추기는 한다.- 뒤에
|| true를 붙이면 스크립트는 다음 줄까지 갔고 풀린 파일은 0개였으며 종료 코드는 0이었다. 오류 문구도 없고 파일도 없다.
$ tar -xf ../x.tar --wildcards 'src/*.txt' 2>/dev/null || true; echo "rc=$? files=$(find . -type f | wc -l | tr -d ' ')"
rc=0 files=0
|| true 나 2>/dev/null 은 옵션 이름이 틀렸을 때도 똑같이 조용해진다. 이 줄 뒤에 파일이 풀렸다고 가정하는 명령이 있다면 그 명령이 없는 파일을 찾다가 다른 곳에서 실패한다. 풀린 파일 수를 세어 0이면 멈추게 하는 한 줄이 가장 값싼 안전장치다.
옵션 없이 쓰는 패턴이 맞는 범위
옵션을 빼면 되는 건 알았다. 그럼 맥의 패턴은 정확히 무엇을 맞출까. 멤버가 일곱 개인 아카이브를 만들어 따옴표로 막은 패턴을 하나씩 tar -tf 로 쟀다. 멤버는 top.txt, notes.txt.bak, proj/a.txt, proj/d.log, proj/my file.txt, proj/sub/b.txt, proj/sub/deep/c.txt 이다.
| 패턴 | 맞은 멤버 | 종료 코드 |
|---|---|---|
'*.txt' |
proj/a.txt, proj/my file.txt, proj/sub/b.txt, proj/sub/deep/c.txt, top.txt (5개) |
0 |
'proj/*.txt' |
proj 아래 .txt 4개 (하위 폴더 안 것 포함) |
0 |
'proj/sub' |
그 아래 파일 2개 | 0 |
'*/b.txt' |
proj/sub/b.txt |
0 |
'proj/?.txt' |
proj/a.txt |
0 |
'*.TXT' |
없음, Not found in archive |
1 |
'proj/a' |
없음, Not found in archive |
1 |
세 가지를 알 수 있다. 첫째, 별표가 슬래시를 넘는다. '*.txt' 가 최상위 top.txt 만이 아니라 두 단계 아래의 proj/sub/deep/c.txt 까지 맞췄고, 'proj/*.txt' 도 proj/sub/b.txt 를 맞췄다. 한 폴더 안의 파일만 풀 생각으로 별표를 썼다면 더 많이 풀린다. 둘째, 대소문자를 구분한다. '*.TXT' 는 하나도 못 맞췄다. 셋째, 이름의 일부만으로는 안 맞는다. 'proj/a' 는 proj/a.txt 의 앞부분인데도 못 찾았다. 반대로 폴더 이름 'proj/sub' 은 그 아래 파일을 모두 데려왔다. notes.txt.bak 는 '*.txt' 에 걸리지 않았으니 끝까지 맞아야 하는 패턴이다.
tar -cf x.tar . 처럼 현재 폴더를 통째로 묶으면 멤버 이름이 ./proj/a.txt 처럼 ./ 로 시작한다. 이 맥에서는 'proj/a.txt' 와 './proj/a.txt' 가 둘 다 ./proj/a.txt 를 맞췄고 'top.txt' 와 './top.txt' 도 마찬가지였다. 접두어 ./ 를 신경 쓰지 않아도 됐다. 풀 때도 같아서 --strip-components=1 을 함께 주고 'proj/*.txt' 로 풀면 a.txt, my file.txt, sub/b.txt, sub/deep/c.txt 네 개가 한 단계 벗겨진 채 풀렸다. 패턴은 벗기기 전의 이름과 맞춘 것으로 읽힌다.
같은 아카이브를 GNU tar 1.35 로 읽으면
GNU 설명서의 “Controlling Pattern-Matching” 은 명령줄에 준 멤버 이름이 기본으로 글롭이 아니라 문자 그대로 비교되고 --wildcards 를 줘야 패턴이 된다고 적는다. 같은 아카이브에 직접 빌드한 GNU tar 1.35 를 대 보니 그대로였다. 옵션 없이 '*.txt' 를 주면 Not found in archive 와 종료 코드 2에, “Use –wildcards to enable pattern matching, or –no-wildcards to suppress this warning” 경고가 붙었고, 글롭 글자가 없는 'proj/sub' 과 'proj/a.txt' 는 종료 코드 0으로 맞았다.
--wildcards 를 붙이면 결과는 이 맥의 bsdtar 와 같았다. '*.txt' 는 여섯 멤버(이 아카이브는 proj/file[1].txt 가 하나 더 있다), 'proj/*.txt' 는 다섯, '*/b.txt' 는 하나를 맞췄고 '*.TXT' 와 'proj/a' 는 못 찾았다. 설명서의 기본값 표만 읽으면 이름을 지정한 멤버에서 별표가 슬래시를 넘지 않을 것처럼 읽히지만, 실행해 보니 --wildcards 만 줘도 별표는 슬래시를 넘었고 --wildcards-match-slash 를 더해도 결과가 같았다. 같은 설명서 페이지에 “wildcards can match /” 라는 문장이 따로 있어서 표와 문장이 엇갈려 보이는데, 실행 결과는 문장 쪽이었다.
갈린 곳은 셋이다. 첫째, ./ 접두어다. tar -cf x.tar . 로 묶은 아카이브에서 GNU 는 --wildcards 'proj/a.txt' 를 Not found in archive 와 종료 코드 2로 못 찾았고 './proj/a.txt' 와 '*/a.txt' 는 맞았다. 이 맥의 bsdtar 는 'proj/a.txt' 도 맞췄다. 설명서가 “patterns and names are used as-is” 라고 한 대로 GNU 는 접두어를 떼지 않는 것으로 읽힌다. 둘째, 못 찾았을 때의 종료 코드가 bsdtar 는 1, GNU 는 2다. 종료 코드를 1과 비교하는 스크립트는 한쪽에서만 맞는다. 셋째, 맥의 tar 로 만든 아카이브에는 ._ 로 시작하는 메타데이터 항목이 들어 있었다. GNU 목록에는 그런 항목이 열한 개 보였고 이 맥의 bsdtar 목록에는 0개였으며, GNU --wildcards '*.txt' 는 그중 여섯 개를 맞췄다. 같은 아카이브를 아래 함수로 GNU tar 에서 풀어 보니 여섯 파일과 함께 ._ 항목 여섯 개도 풀려 전체가 12개였다. ._ 가 맥 파일의 부가 정보를 담은 항목으로 보이는 것은 짐작이고 확인하지 않았다. 풀린 파일 수를 세어 점검하는 스크립트라면 이 수가 맥에서 센 수와 다를 수 있다.
대괄호 이름은 --wildcards 를 줄 때만 같았다. GNU 는 옵션 없이 'proj/file[1].txt' 를 글자 그대로 맞췄지만 이 맥의 bsdtar 는 정확한 이름을 불러도 못 찾는다. GNU 도 --wildcards 를 주면 못 찾았고 이스케이프한 'proj/file\[1\].txt' 는 둘 다 맞았다.
따옴표를 빼면 셸이 먼저 푼다
패턴을 따옴표로 막으라는 말이 왜 나오는지도 쟀다. 현재 폴더에 a.txt 가 하나 있는 상태에서 tar -tf ../x.tar *.txt 를 따옴표 없이 쓰면 bash 가 *.txt 를 a.txt 로 바꿔 tar 에 넘기므로 ./a.txt 하나만 나왔고 종료 코드는 0이었다. 따옴표를 쓰면 아카이브 안의 ./a.txt, ./sub/b.txt, ./sub/file[1].txt 세 개가 나왔다. 오류도 없이 결과가 달라진다.
현재 폴더에 맞는 파일이 없을 때는 셸마다 달랐다. bash 3.2 는 *.txt 를 글자 그대로 tar 에 넘겨 세 개가 나왔다. zsh 5.9 는 zsh:1: no matches found: *.txt 를 찍고 tar 를 실행하지 않았다. 같은 스크립트가 어느 셸에서, 어느 폴더에서 도는지에 따라 달라지니 패턴은 항상 따옴표로 막는다.
못 찾은 패턴은 종료 코드 1로 알려 준다
맞는 멤버가 없는 패턴은 tar: nope.txt: Not found in archive 와 tar: Error exit delayed from previous errors. 두 줄과 종료 코드 1을 낸다. 일부만 못 찾았을 때도 같았다. tar -xf ../x.tar a.txt nope.txt 는 a.txt 는 풀고 nope.txt 만 오류를 내며 종료 코드 1로 끝났고, 2>/dev/null 을 붙여도 종료 코드는 1이었다. 옵션 거부와 달리 패턴을 못 찾은 쪽은 풀 수 있는 것은 풀고 나서 알린다. 그래서 set -e 없이 종료 코드를 보지 않으면 일부만 풀린 채 지나간다. 위에서 적었듯 GNU tar 1.35 는 같은 상황에서 종료 코드 2를 냈다.
이름에 대괄호나 별표가 든 멤버
맥에서는 정확한 이름을 불러도 패턴으로 읽힌다. 멤버 ./sub/file[1].txt 를 tar -tf x.tar './sub/file[1].txt' 로 부르니 Not found in archive 와 종료 코드 1이었다. [1] 이 숫자 1 한 글자를 가리키는 문자 집합으로 읽혀 file1.txt 를 찾은 것으로 읽힌다(짐작이다). 대괄호를 'sub/file[[]1].txt' 로 바꾸거나 'sub/file\[1\].txt' 처럼 이스케이프하면 맞았고, 'sub/file?1?.txt' 도 맞았다. -T 목록파일 로 ./sub/file[1].txt 를 한 줄 적어 넘겨도 Not found in archive 였고, 이스케이프한 ./sub/file\[1\].txt 를 적으면 맞았다.
별표가 이름에 든 멤버 sub/star*.txt 를 이스케이프 없이 부르면 sub/starX.txt 까지 둘이 풀렸고, 이스케이프하면 하나만 풀렸다. 이름을 그대로 부르는 함수는 이렇게 쓴다.
tarpat_escape() { printf '%s' "$1" | sed 's/[][*?\\]/\\&/g'; }
tar -xf x.tar "$(tarpat_escape 'sub/file[1].txt')"
tar -tf 로 목록을 뽑아 셸 case 로 거른 뒤 이스케이프해 넘기는 방식(멤버 다섯 개의 .txt)도 같은 함수로 모두 풀렸다.
두 종류의 tar 에서 같은 줄을 쓰는 함수
리눅스와 맥에서 같은 스크립트를 돌려야 한다면 tar --version 의 출력으로 종류를 가려 옵션을 붙이거나 뺀다.
tar_flavor() { case "$(tar --version 2>/dev/null)" in *bsdtar*) echo bsd ;; *"GNU tar"*) echo gnu ;; *) echo unknown ;; esac; }
tar_xglob() { # tar_xglob 아카이브 패턴... (패턴은 따옴표로 넘길 것)
local ar=$1; shift
case "$(tar_flavor)" in
bsd) tar -xf "$ar" "$@" ;;
gnu) tar -xf "$ar" --wildcards "$@" ;;
*) echo "tar_xglob: 종류를 알 수 없다" >&2; return 2 ;;
esac
}
이 맥에서 tar_flavor 는 bsd 를 냈고 tar_xglob ../x.tar '*.txt' 는 .txt 다섯 개를 풀며 종료 코드 0이었다. '*.TXT' 는 Not found in archive 와 종료 코드 1, 풀린 파일 0개였다. gnu 가지는 직접 빌드한 GNU tar 1.35 를 PATH 맨 앞에 tar 라는 이름으로 두고 돌렸다. tar_flavor 는 gnu 를 냈고 tar_xglob ../plain.tar '*.txt' 는 ._ 항목을 뺀 여섯 개를(._ 여섯 개가 같이 풀려 전체 12개) 종료 코드 0으로 풀었으며 '*.TXT' 는 Not found in archive, 종료 코드 2에 풀린 파일 0개였다. 종류에 따라 못 찾았을 때의 종료 코드가 1과 2로 갈리므로 호출하는 쪽은 0인지 아닌지만 본다.
bsdtar 에는 --include '패턴' 과 --exclude '패턴' 도 있었다. --include '*.txt' 로 풀면 .txt 다섯 개만, --exclude '*.txt' 로 풀면 c.log 만 풀렸다. GNU tar 와 이름이 같은 옵션이 아니므로 두 곳에서 같은 줄로 쓰기는 어렵다.
맥에서만 쓰는 스크립트라면 옵션을 빼고 패턴을 따옴표로 막는 것이 가장 짧다. 리눅스와 같이 쓰는 스크립트라면 위 함수로 가르거나, GNU tar 를 brew install gnu-tar 로 설치해 gtar 로 부르는 길이 있다. 이 글은 설치를 시험하지 않았다. 어느 쪽이 나은지는 시험이 아니라 이 글의 판단이다.
시험하지 못한 것
리눅스 배포판이 싣는 GNU tar(내가 쓴 것은 이 맥에서 빌드한 1.35 한 가지다), 다른 버전의 GNU tar, BusyBox tar, 압축 형식별 차이(-z·-j·.zip), 같은 이름 멤버가 여러 개인 아카이브, 절대 경로나 .. 가 든 멤버, -k·-U 같은 덮어쓰기 옵션, -s 이름 바꾸기와 패턴을 함께 쓴 경우, 한글 이름 멤버는 시험하지 않았다. 멤버가 두 개에서 여덟 개인 작은 아카이브 몇 개에서 쟀다. 같은 오류 문구를 직접 다룬 질문 페이지는 웹 검색 두 번으로 찾지 못했고 검색량은 확인하지 않았다.
세 줄 요약
- 맥(26.6.2)의 tar 는 –wildcards 를 포함한 GNU 패턴 옵션 여섯 개를 종료 코드 1로 거부하고, 옵션을 뺀 따옴표 패턴은 그대로 풀린다.
- 오류를 || true 로 덮으면 풀린 파일 0개에 종료 코드 0으로 지나가며, 따옴표를 빼면 현재 폴더 파일로 셸이 먼저 풀어 결과가 달라진다.
- 맥의 패턴은 별표가 슬래시를 넘고 대소문자를 구분하며 대괄호 이름은 이스케이프해야 하고, GNU tar 1.35 와는 ./ 접두어 처리와 못 찾은 종료 코드(1 대 2)가 갈렸다.
To help a reader who ran a Linux-style tar --wildcards line on a Mac and hit an error, or whose script hid the error and moved on having extracted nothing, learn how to do the same job with the Mac's tar and where the results diverge.
The bsdtar 3.5.3 on this Mac (26.6.2) rejects six GNU pattern options, including --wildcards, with exit code 1. Dropping the option and quoting the pattern makes the same line work, but on this Mac the asterisk crosses slashes and matches files in deep folders, matching is case-sensitive, and a member whose name contains brackets is not found when called by its exact name. When the error is discarded, the line can pass with zero files extracted and exit code 0.
Find the lines in your scripts that put --wildcards on tar, drop the option, and check that the pattern is quoted. If any of those lines discards its error with 2>/dev/null or || true, add a check that counts the extracted files.
Contents
- The pattern options the Mac’s tar rejects
- When the error is discarded, zero files come out and the line passes
- How far a pattern matches without the option
- Reading the same archive with GNU tar 1.35
- Without quotes, the shell expands it first
- A pattern with no match is reported with exit code 1
- Members whose names contain brackets or asterisks
- A function that uses the same line with both kinds of tar
- What I could not test
- Three-line summary
One-line summary: The Mac’s tar rejects the six GNU pattern options I tried with exit code 1, so drop –wildcards and quote the pattern, but check that the asterisk crosses slashes, that bracket names need escaping, and that GNU differs on the ./ prefix and the exit code.
If you run the Linux line tar -xf app.tar --wildcards '*.txt', which extracts only the .txt files inside an archive, in a Mac terminal, nothing is extracted and only an error message remains. This article shows, from runs on this Mac, what the Mac’s tar rejects, what state a script that discards the error is in on the next line, whether dropping the option does the same job, and exactly how far the patterns used without the option match on this Mac.
tar: Option --wildcards is not supported
Usage:
List: tar -tf <archive-filename>
Extract: tar -xf <archive-filename>
Create: tar -cf <archive-filename> [filenames...]
Help: tar --help
The environment I checked is /usr/bin/tar (bsdtar 3.5.3 - libarchive 3.7.4) on macOS 26.6.2 arm64, bash 3.2.57, zsh 5.9 and LC_ALL=C, dated 2026-11-04. I ran six test scripts twice each, and the second output was identical to the first down to the character. GNU tar is not on this Mac, so I downloaded the tar 1.35 source from gnu.org and built it on this Mac for the comparison. It is a GNU tar 1.35 built on this Mac, not the tar of a Linux distribution. The manual page I read is the 1.35.90 version.
A few terms. An exit code is the number a command leaves when it ends, and 0 means success. GNU tar is the tar of many Linux distributions, while the Mac’s tar is the BSD-family bsdtar (libarchive), so the names match but the options differ. A member is the name of each file entry inside an archive. A pattern is a group of names written with * or ? (a glob), and it is quoted so that the shell does not expand it into file names first.
The pattern options the Mac’s tar rejects
I made an archive from a folder src holding a.txt, b.log and c.txt, and changed only the option in tar -tf x.tar option 'src/*.txt'. --wildcards, --no-wildcards, --wildcards-match-slash, --no-wildcards-match-slash, --anchored and --no-anchored all gave exit code 1, and the error named the option as it was, like tar: Option --wildcards is not supported.
With only the option removed from the same line, the exit code was 0 and src/a.txt and src/c.txt came out. The Mac’s man tar also gives, for listing and extracting, only the form tar {-t | -x} [options] [patterns] and describes the patterns as “shell-style globbing patterns as documented in tcsh(1)”. The Mac’s tar reads patterns as globs without being told to, so there is no place to attach the option.
A public script from April 2024 (a gist for releasing Iris and std++) records the same situation in comments. The two lines are “if tar is GNU tar, we need –wildcards” and “BSD tar interprets patterns with wildcards by default and has no such option”, and its code adds --wildcards only when tar --version shows “GNU tar”.
When the error is discarded, zero files come out and the line passes
I tested a script that added 2>/dev/null because the option error was noisy. In an empty folder, tar -xf ../x.tar --wildcards 'src/*.txt' 2>/dev/null had exit code 1 and 0 extracted files. The same line with only the option removed had exit code 0 and extracted the two files ./src/a.txt and ./src/c.txt.
- In a bash script with
set -e, the script stopped at this line with exit code 1 and the nextechodid not run. So even with the error discarded, it does stop. - With
|| trueadded, the script went on to the next line with 0 extracted files and exit code 0. There is no error message and no files.
$ tar -xf ../x.tar --wildcards 'src/*.txt' 2>/dev/null || true; echo "rc=$? files=$(find . -type f | wc -l | tr -d ' ')"
rc=0 files=0
|| true and 2>/dev/null make a wrong option name just as quiet. If any command after this line assumes the files were extracted, it will look for files that are not there and fail somewhere else. A one-line check that counts the extracted files and stops at 0 is the cheapest safeguard.
How far a pattern matches without the option
Dropping the option works, but what exactly does the Mac’s pattern match? I made an archive with seven members and measured the quoted patterns one by one with tar -tf. The members are top.txt, notes.txt.bak, proj/a.txt, proj/d.log, proj/my file.txt, proj/sub/b.txt and proj/sub/deep/c.txt.
| Pattern | Members matched | Exit code |
|---|---|---|
'*.txt' |
proj/a.txt, proj/my file.txt, proj/sub/b.txt, proj/sub/deep/c.txt, top.txt (5) |
0 |
'proj/*.txt' |
4 .txt files under proj (including those in subfolders) |
0 |
'proj/sub' |
the 2 files below it | 0 |
'*/b.txt' |
proj/sub/b.txt |
0 |
'proj/?.txt' |
proj/a.txt |
0 |
'*.TXT' |
none, Not found in archive |
1 |
'proj/a' |
none, Not found in archive |
1 |
Three things follow. First, the asterisk crosses slashes. '*.txt' matched not only the top-level top.txt but also proj/sub/deep/c.txt two levels down, and 'proj/*.txt' also matched proj/sub/b.txt. If you used an asterisk meaning to extract only the files directly in one folder, more files come out. Second, matching is case-sensitive. '*.TXT' matched nothing. Third, a pattern does not match just part of a name. 'proj/a', the beginning of proj/a.txt, was not found. On the other hand the folder name 'proj/sub' brought in every file below it. notes.txt.bak was not caught by '*.txt', so the pattern has to match to the end.
If you wrap the current folder whole, as in tar -cf x.tar ., the member names start with ./, like ./proj/a.txt. On this Mac both 'proj/a.txt' and './proj/a.txt' matched ./proj/a.txt, and 'top.txt' and './top.txt' were the same. I did not need to worry about the ./ prefix. Extraction was the same: giving --strip-components=1 and extracting with 'proj/*.txt' extracted four files, a.txt, my file.txt, sub/b.txt and sub/deep/c.txt, with one level stripped. It reads as though the pattern is matched against the name before stripping.
Reading the same archive with GNU tar 1.35
The “Controlling Pattern-Matching” section of the GNU manual says that member names given on the command line are by default compared literally, not as globs, and that you need --wildcards to make them patterns. Pointing the GNU tar 1.35 I built at the same archive, that is what happened. Giving '*.txt' without the option produced Not found in archive and exit code 2, plus the warning “Use –wildcards to enable pattern matching, or –no-wildcards to suppress this warning”, while 'proj/sub' and 'proj/a.txt', which contain no glob characters, matched with exit code 0.
With --wildcards added, the results were the same as this Mac’s bsdtar. '*.txt' matched six members (this archive has one more, proj/file[1].txt), 'proj/*.txt' five and '*/b.txt' one, and '*.TXT' and 'proj/a' were not found. Reading only the manual’s table of defaults makes it sound as if an asterisk would not cross a slash in a named member, but when I ran it the asterisk crossed slashes with --wildcards alone, and adding --wildcards-match-slash gave the same result. The same manual page has a separate sentence saying “wildcards can match /”, so the table and the sentence look contradictory, and the run followed the sentence.
There were three differences. First, the ./ prefix. In an archive packed with tar -cf x.tar ., GNU did not find --wildcards 'proj/a.txt', giving Not found in archive and exit code 2, while './proj/a.txt' and '*/a.txt' matched. This Mac’s bsdtar matched 'proj/a.txt' too. It reads as though GNU does not strip the prefix, in line with the manual’s “patterns and names are used as-is”. Second, the exit code when nothing is found is 1 for bsdtar and 2 for GNU. A script that compares the exit code with 1 is right on only one of them. Third, the archive made by the Mac’s tar contained metadata entries starting with ._. The GNU listing showed eleven of them and this Mac’s bsdtar listing showed none, and GNU --wildcards '*.txt' matched six of them. When I extracted the same archive with the function below under GNU tar, the six files came out together with six ._ entries, 12 in all. That ._ marks entries holding a Mac file’s extra information is a guess I did not confirm. A script that checks by counting extracted files may see a different number from the one it counted on the Mac.
Bracket names were the same only when --wildcards was given. GNU matched 'proj/file[1].txt' literally without the option, but this Mac’s bsdtar does not find the exact name. GNU also failed to find it with --wildcards, and both matched the escaped 'proj/file\[1\].txt'.
Without quotes, the shell expands it first
I also tested why people say to quote the pattern. With one file a.txt in the current folder, tar -tf ../x.tar *.txt without quotes made bash turn *.txt into a.txt before passing it to tar, so only ./a.txt came out, with exit code 0. With quotes, three came out from inside the archive: ./a.txt, ./sub/b.txt and ./sub/file[1].txt. The result differs without any error.
When no file in the current folder matched, the shells differed. bash 3.2 passed *.txt to tar as literal characters and three came out. zsh 5.9 printed zsh:1: no matches found: *.txt and did not run tar. The outcome depends on which shell and which folder the same script runs in, so always quote the pattern.
A pattern with no match is reported with exit code 1
A pattern that matches no member prints two lines, tar: nope.txt: Not found in archive and tar: Error exit delayed from previous errors., with exit code 1. It was the same when only some of the patterns were missing. tar -xf ../x.tar a.txt nope.txt extracted a.txt, gave an error only for nope.txt and ended with exit code 1, and the exit code was still 1 even with 2>/dev/null. Unlike the option rejection, a pattern that is not found extracts what it can and reports afterwards. So without set -e and without looking at the exit code, the script goes on with only some of the files extracted. As noted above, GNU tar 1.35 gave exit code 2 in the same situation.
Members whose names contain brackets or asterisks
On the Mac, even an exact name is read as a pattern. Calling the member ./sub/file[1].txt as tar -tf x.tar './sub/file[1].txt' gave Not found in archive and exit code 1. It reads as though [1] was taken as a character set meaning the single character 1 and the search was for file1.txt (this is a guess). Changing the brackets to 'sub/file[[]1].txt' or escaping them as 'sub/file\[1\].txt' matched, and 'sub/file?1?.txt' matched too. Passing the name through -T listfile with ./sub/file[1].txt on one line also gave Not found in archive, and writing the escaped ./sub/file\[1\].txt matched.
Calling the member sub/star*.txt, whose name contains an asterisk, without escaping extracted two, including sub/starX.txt, and with escaping extracted one. A function for calling a name exactly looks like this.
tarpat_escape() { printf '%s' "$1" | sed 's/[][*?\\]/\\&/g'; }
tar -xf x.tar "$(tarpat_escape 'sub/file[1].txt')"
Listing the members with tar -tf, filtering them with a shell case, then escaping and passing them on (five .txt members) also extracted all of them with the same function.
A function that uses the same line with both kinds of tar
If you must run the same script on Linux and the Mac, tell the kinds apart by the output of tar --version and add or drop the option.
tar_flavor() { case "$(tar --version 2>/dev/null)" in *bsdtar*) echo bsd ;; *"GNU tar"*) echo gnu ;; *) echo unknown ;; esac; }
tar_xglob() { # tar_xglob archive pattern... (pass patterns in quotes)
local ar=$1; shift
case "$(tar_flavor)" in
bsd) tar -xf "$ar" "$@" ;;
gnu) tar -xf "$ar" --wildcards "$@" ;;
*) echo "tar_xglob: cannot tell the kind of tar" >&2; return 2 ;;
esac
}
On this Mac tar_flavor printed bsd, and tar_xglob ../x.tar '*.txt' extracted five .txt files with exit code 0. '*.TXT' gave Not found in archive, exit code 1 and 0 extracted files. I ran the gnu branch by putting the GNU tar 1.35 I built at the front of PATH under the name tar. tar_flavor printed gnu, tar_xglob ../plain.tar '*.txt' extracted six files excluding the ._ entries (six ._ entries came out with them, 12 in all) with exit code 0, and '*.TXT' gave Not found in archive, exit code 2 and 0 extracted files. Because the exit code for not found differs between 1 and 2 by kind, the caller should only check whether it is 0. (The tested function prints its message in Korean; the English message above is a translation for this page.)
bsdtar also had --include 'pattern' and --exclude 'pattern'. Extracting with --include '*.txt' extracted only five .txt files, and with --exclude '*.txt' only c.log. They are not options with the same names as GNU tar’s, so it is hard to use them in the same line in both places.
If the script is only for Mac, dropping the option and quoting the pattern is the shortest. If it is shared with Linux, you can split with the function above, or install GNU tar with brew install gnu-tar and call it as gtar. This article did not test the installation. Which is better is this article’s judgment, not a test result.
What I could not test
I did not test the GNU tar that Linux distributions ship (the one I used is a 1.35 built on this Mac), other versions of GNU tar, BusyBox tar, differences by compression format (-z, -j, .zip), archives with several members of the same name, members with absolute paths or .., overwrite options such as -k and -U, using -s renaming together with patterns, or members with Korean names. I measured on a few small archives of two to eight members. I could not find a question page that deals directly with this error message in two web searches, and I did not check search volume.
Three-line summary
- The Mac’s (26.6.2) tar rejects six GNU pattern options, including –wildcards, with exit code 1, and a quoted pattern with the option removed extracts as expected.
- Covering the error with || true passes with 0 files extracted and exit code 0, and without quotes the shell first expands the pattern into files in the current folder, so the result changes.
- On the Mac the asterisk crosses slashes, matching is case-sensitive and bracket names must be escaped, and GNU tar 1.35 differed in ./ prefix handling and in the not-found exit code (1 versus 2).