首页 > Sysadmin > 正文

Linux tar Pitfalls: 3 Default Behaviors That Bite

2026-10-27 Sysadmin

tar’s pitfalls cluster in three places: which word -f eats, whether extraction overwrites same-named files, and how links are stored. All conclusions below were measured in WSL.

Packing: -f always eats the word right after it

mkdir -p /tmp/demo/src && echo hello > /tmp/demo/src/a.txt
tar cfz good.tar.gz /tmp/demo/src      # f 的值是 good.tar.gz
tar -cfz bad.tar.gz /tmp/demo/src      # f 的值是 z:落地的ARCHIVE文件叫 z

The manual’s rule: short options can be bundled, but an option that takes an argument must stay at the end of the letter cluster, otherwise the word right after it is taken as that argument [1]. Measured, the two commands end differently: the first produces good.tar.gz; the second prints tar: bad.tar.gz: Cannot stat: No such file or directory, exits 2, and drops an archive literally named z in the current directory. Writing the operation, the flags, and the archive name separately (tar -czf good.tar.gz <path>) is harder to get wrong.

Extracting: same-named files are overwritten by default; protect them with –keep-newer-files

tar -tvf good.tar.gz                            # 先看清单再决定解到哪
mkdir -p out && tar -xf good.tar.gz -C out       # -C 指定解包目录
tar -xvf good.tar.gz -C out './a.txt'            # 只取一个成员:名字照 -t 的输出写
tar -xvf good.tar.gz --keep-newer-files -C out './a.txt'

Measured: extraction overwrites same-named files by default — an a.txt on disk that was newer than the archive got replaced by the archive’s copy; with --keep-newer-files the very same command prints Current './a.txt' is newer or same age and keeps the on-disk version, exit code still 0 [3]. The manual defines --overwrite as “overwrite existing files when extracting” and --keep-newer-files as “do not replace files that are newer than their archive copies” [2], matching the test. If -C points at a nonexistent directory, tar reports Cannot open: No such file or directory and exits 2 (measured). Reading a compressed archive needs no -z: measured, tar -tf and tar -xf work on .tar.gz directly; but appending to a compressed archive reports Cannot update compressed archives with exit code 2 (measured) [2].

Extracting one member: wildcards must be enabled explicitly and must match the whole member name

tar -tf good.tar.gz | head -4                     # 成员名带前缀,如 tmp/demo/src/a.txt
tar -xf good.tar.gz --wildcards -C out 'sub/*.txt'
tar -xf good.tar.gz --wildcards --no-anchored -C out '*.txt'

The manual’s rule: wildcards are for exclusion only by default; to select members you must add --wildcards explicitly, and member names must match what --list prints [1][2]. Measured and consistent: without --wildcards tar reports Pattern matching characters used in file names (exit 2); with it, sub/*.txt still matches nothing (matching is anchored to the start of the name by default), and only --no-anchored succeeds. The quotes are not optional — tar -xf a.tar *.txt lets the shell expand the glob against on-disk files first; measured, it reports a.txt: Not found in archive. To avoid typing the whole prefix, use --strip-components=1 (measured: the contents land at the root of the target directory).

Paths and links: the leading / is stripped; symlinks and hard links are stored as links

tar -cf abs.tar /tmp/demo/src                     # 打印 Removing leading `/' 的警告
tar -cf abs2.tar -P /tmp/demo/src                  # -P 保留绝对路径
tar -C /tmp/demo/src -cf link.tar a.txt hard link  # 硬链接和符号链接按链接存
tar -C /tmp/demo/src --hard-dereference -cf dl.tar a.txt hard
tar cf - -C /tmp/demo/src . | (mkdir -p dest && cd dest && tar xf -)

The manual’s rule: tar makes member names relative both when archiving and when restoring (stripping the leading /); keeping them requires --absolute-names explicitly, and names with a leading / or internal .. get special treatment during extraction [1][3]. Measured, both commands exit 0 and only the first prints that warning. An archive made with -P lands by absolute path — run tar -tvf and read the member names before using one. On links: measured, a symlink is stored as the link itself (-tvf shows link -> a.txt), a hard link is stored as a link member pointing at the first member (hard link to a.txt), and after extraction they still share one inode with link count 2; only --dereference or --hard-dereference switches to storing the target’s content [2]. Using - at both ends of a pipe reads and writes stdin/stdout; measured, diff -r shows byte-identical results [3]. Extracting as non-root turns the owner into the extracting user — the manual says --same-owner and -p default to the superuser only [3]; measured, permissions land per the mode recorded in the archive (640) while the owner becomes an ordinary user.

Rollback and a troubleshooting cheat-sheet

tar has no undo. The safe order is: check member names with tar -tvf, extract into an empty directory, verify with diff -r before touching the original directory; before overwriting existing files, back them up first or add --keep-newer-files.

| Symptom | Cause | Fix | |—|—|—| | Cannot stat: No such file or directory, archive name eaten | a spelling like -cfz takes the next word as f’s argument [1] | keep f at the end of the letter cluster | | Removing leading '/' from member names | member names are made relative by default [1] | use -P to keep absolute paths; read the member names first | | Pattern matching characters used in file names | wildcards are off by default when selecting members [2] | add --wildcards explicitly, pair with --no-anchored when needed | | Not found in archive | the member name doesn’t match -t output, or the glob was expanded by the shell first | copy it straight from -t output and quote it | | Same-named files overwritten after extraction | overwrite by default [2] | --keep-newer-files, or back up first | | Cannot update compressed archives | compressed archives can’t be appended or concatenated [3] | repack, or decompress first, then edit and recompress |

FAQ and limitations

Does reading a compressed archive need -z — no, measured to work directly; creation uses -z or --auto-compress (picks the compressor from the archive suffix) [1]. Exit-code rule: 0 success, 1 files differ or were changed, 2 fatal error [1][3]; measured, the exit-2 cases came from Cannot stat / Cannot open / Cannot update; the exit-1 scenario (a file changed during packing) couldn’t be reproduced under WSL — documentation-checked only.

Status: draft pending review. Test environment: WSL2 Ubuntu 24.04.4 LTS, GNU tar 1.35 (tar --version), dated 2026-10-26. Actually tested: the two spellings landing different archive names; default overwrite vs --keep-newer-files; member-name anchoring with --wildcards/--no-anchored; leading-/ stripping and -P; symlink and hard-link storage and the post-extract link count; -C with a nonexistent directory; no append on compressed archives; piping with -f -; --strip-components; non-root owner and permissions. Documentation-checked only, not yet executed: the exit-code-1 trigger; default behaviors of bsdtar on BSD/macOS and busybox tar; cross-filesystem archiving (filesystems without hard-link support) and archiving other users’ files as non-root.


References

The main commands in this article were tested on WSL Ubuntu (24.04); a few items (missing tools / install-type commands) were only verified against official documentation, not executed.