tar packs files and directories into one archive file, keeping names, permissions, owners and timestamps, and unpacks them again. On Debian, Ubuntu, Fedora and Arch, tar is GNU tar. On macOS and FreeBSD, tar is bsdtar from libarchive. The two share the everyday flags and differ in the corners, and this sheet marks each difference it covers. Every flag below is from the GNU tar manual or the bsdtar man page. The GNU examples were run with GNU tar 1.35 and the bsdtar examples with bsdtar 3.7.4 on Linux. We attempt to test on all versions. Nothing on this page was run on macOS, so macOS-only notes say "per the bsdtar man page (not run on macOS)".
what it is and when to use it
- Archive: one file holding many files plus their metadata. A plain
.tarisn’t compressed. - Compressed archive: the same tar stream run through gzip, bzip2, xz or zstd, giving
.tar.gz(or.tgz),.tar.bz2,.tar.xzor.tar.zst. - Member: one file, directory or link inside the archive, stored under the path you gave when you created it.
- Mode: every tar command does exactly one of
-c(create),-t(list),-x(extract),-r(append),-u(update), or in GNU tar-d(compare) and--delete.-fnames the archive file, and-f -means stdin or stdout.
Reach for it to back up or ship a directory as one file, to copy a tree with its permissions intact (including across ssh), and to unpack the source tarballs and release downloads that still come as .tar.gz or .tar.xz.
install and check the version
GNU tar is the tar package on Debian, Ubuntu, Fedora and Arch, and macOS ships bsdtar as /usr/bin/tar. To add the other one, sudo apt install libarchive-tools installs bsdtar on Debian or Ubuntu, and brew install gnu-tar installs GNU tar on macOS as gtar.
| Command | What it does |
|---|---|
tar --version | head -1 bsdtar --version output tar (GNU tar) 1.35 bsdtar 3.7.4 - libarchive 3.7.4 zlib/1.3.1 liblzma/5.8.1 bz2lib/1.0.8 liblz4/1.10.0 libzstd/1.5.7 | Which tar is this? GNU tar prints "tar (GNU tar)", bsdtar prints "bsdtar" |
create, list, extract
| Command | What it does |
|---|---|
tar -cf proj.tar proj | REPLACES ARCHIVE: create proj.tar from the directory proj (an existing proj.tar is overwritten) |
tar -tf proj.tar | List the member names |
tar -tvf proj.taroutput drwxr-xr-x box/box 0 2026-10-25 09:00 proj/ drwxr-xr-x box/box 0 2026-10-25 09:00 proj/logs/ -rw-r--r-- box/box 9 2026-10-25 09:00 proj/logs/app.log -rwxr-xr-x box/box 19 2026-10-25 09:00 proj/run.sh | List with permissions, owner, size and date (output trimmed to four lines) |
bsdtar’s -tvf prints an ls -l style line instead, such as -rw-r--r-- 0 box box 7 Oct 25 09:00 proj/README.md.
| Command | What it does |
|---|---|
tar -xf proj.tar | OVERWRITES: extract everything into the current directory |
tar -xkf proj.taroutput tar: proj/README.md: Cannot open: File exists tar: Exiting with failure status due to previous errors | Extract, but refuse to replace files that already exist (GNU and bsdtar) |
That output is trimmed to one of the eight "File exists" lines. GNU tar exits 2 but leaves the existing files alone. bsdtar 3.7.4 kept the existing file too, silently, with exit status 0. GNU’s --skip-old-files skips them without errors.
| Command | What it does |
|---|---|
tar -cvf proj.tar proj | Print each name as it’s archived (verbose) |
GNU tar’s verbose create prints plain names (proj/README.md). bsdtar prefixes each with a (a proj/README.md). Peeking inside a .tar.gz without unpacking is in the archives one-liners.
compression: gzip, bzip2, xz, zstd
Add one letter to compress on the way out. When extracting or listing from a file, both GNU tar and bsdtar detect the compression themselves, so tar -xf works for every row below.
| Command | What it does |
|---|---|
tar -czf proj.tar.gz proj | REPLACES ARCHIVE: gzip (.tar.gz or .tgz) |
tar -cjf proj.tar.bz2 proj | REPLACES ARCHIVE: bzip2 (.tar.bz2) |
tar -cJf proj.tar.xz proj | REPLACES ARCHIVE: xz (.tar.xz) |
tar --zstd -cf proj.tar.zst proj | REPLACES ARCHIVE: zstd (GNU tar 1.31 and later, and bsdtar) |
tar -caf proj.tar.zst proj | REPLACES ARCHIVE: let -a pick the compression from the suffix |
tar -xf proj.tar.xz -C restore | OVERWRITES files of the same name in restore/: extract any of them, compression detected from the file |
tar -I 'zstd -19 -T0' -cf proj-19.tar.zst proj | GNU: pass options to the compressor (zstd level 19, all cores) |
bsdtar --zstd --options zstd:compression-level=19 -cf proj-19.tar.zst proj | bsdtar: the same compression level through --options |
Without -a, the letter flag wins over the file name. tar -czf wrong.tar.zst proj still writes gzip:
wrong.tar.zst: gzip compressed data, from Unix, original size modulo 2^32 20480
That’s file wrong.tar.zst. With -a, the suffix wins: tar -cajf aj.tgz proj wrote gzip in both tars. With a suffix neither knows (unk.xxx), -caf wrote an uncompressed archive and -cajf wrote bzip2, in both tars. How small and how fast each compressor is depends on your data, so try them on your own files.
extract into another directory with -C
| Command | What it does |
|---|---|
mkdir -p ~/restore && tar -xzf proj.tar.gz -C ~/restore | OVERWRITES files of the same name under ~/restore: extract there instead of the current directory |
-C doesn’t create the directory. If it’s missing, GNU tar stops with exit status 2:
tar: /tmp/tl-tar/no-such-dir: Cannot open: No such file or directory tar: Error is not recoverable: exiting now
bsdtar says bsdtar: could not chdir to '/tmp/tl-tar/no-such-dir'.
| Command | What it does |
|---|---|
tar -czf proj.tar.gz -C /srv/app proj | REPLACES ARCHIVE: archive /srv/app/proj with relative names, without cd-ing there first |
Members are stored as proj/..., not /srv/app/proj/.... Give tar an absolute path instead and both versions strip the leading /, saying so: tar: Removing leading `/' from member names from GNU, bsdtar: Removing leading '/' from member names from bsdtar.
extract one file or path
Name members exactly as tar -tf prints them.
| Command | What it does |
|---|---|
tar -xf proj.tar proj/src/main.c | OVERWRITES: extract one file (directories on its path are created) |
tar -xf proj.tar proj/src | OVERWRITES: extract one directory and everything under it |
tar -xOf proj.tar.gz proj/README.mdoutput # proj | Print one member to stdout instead of writing it to disk |
tar -xf proj.tar --wildcards 'proj/src/*.c' | OVERWRITES: GNU needs --wildcards for patterns when extracting |
Without --wildcards, GNU tar treats the pattern as a literal name, warns Pattern matching characters used in file names, then fails with tar: proj/src/*.c: Not found in archive and exit status 2.
| Command | What it does |
|---|---|
bsdtar -xf proj.tar 'proj/src/*.c' | OVERWRITES: bsdtar matches patterns by default (it has no --wildcards option) |
An archive made with tar -czf dot.tar.gz -C proj . stores names as ./README.md. GNU tar then fails on README.md with tar: README.md: Not found in archive, so ask for ./README.md. bsdtar accepts README.md for ./README.md.
strip the top directory with --strip-components
Many release tarballs unpack into a versioned directory such as proj-1.2/. --strip-components=N drops the first N path parts from every member name. GNU tar and bsdtar both have it.
| Command | What it does |
|---|---|
mkdir app && tar -xzf proj-1.2.tar.gz -C app --strip-components=1 | OVERWRITES: unpack proj-1.2/* straight into app/ |
mkdir appsrc && tar -xzf proj-1.2.tar.gz -C appsrc --strip-components=2 proj-1.2/src output appsrc appsrc/main.c appsrc/util.c | OVERWRITES: just the src directory’s files, with proj-1.2/src/ stripped off |
The bsdtar man page says members with fewer path parts than N are "silently skipped".
exclude files
The archives one-liners exclude by file pattern. These are the other forms.
| Command | What it does |
|---|---|
tar -cf src.tar --exclude=proj/logs --exclude='*.o' proj | REPLACES ARCHIVE: leave out one directory and every .o file |
tar -cf src.tar --exclude-vcs proj | REPLACES ARCHIVE: leave out .git, .svn, .hg and other version-control directories |
printf '%s\n' 'proj/logs' 'proj/build' '*.env' > excludes.txt tar -cf src.tar -X excludes.txt proj | REPLACES ARCHIVE: read exclude patterns from a file, one per line |
bsdtar has --exclude, --exclude-vcs and -X too. GNU excludes are unanchored, and * matches /. In the test, --exclude=build matched at any depth, --exclude=src/main.c also dropped proj/src/main.c, and --exclude='proj/*.c' dropped proj/src/*.c as well as proj/top.c. A leading / matched nothing. To pin a pattern to the start of the name, put --anchored before it.
Put --exclude before the directory name. Placed after it, GNU tar 1.35 creates the archive anyway, without the exclude, and exits 2:
tar: The following options were used after non-option arguments. These options are positional and affect only arguments that follow them. Please, rearrange them properly. tar: --exclude ‘proj/logs’ has no effect tar: Exiting with failure status due to previous errors
On extract, GNU tar 1.35 applied the exclude wherever it was placed, with no warning and exit status 0. bsdtar treats everything after the first file name as a file name. bsdtar -cf b.tar proj --exclude proj/logs printed bsdtar: --exclude: Cannot stat: No such file or directory, archived proj/logs twice and exited 1.
Leave off the trailing slash: --exclude=proj/logs/ excluded nothing in GNU tar 1.35. Use --exclude=proj/logs, or --exclude='proj/logs/*' to keep the empty directory. bsdtar 3.7.4 excluded the directory with or without the slash.
append, update, delete
These only work on an uncompressed .tar in a regular file, not on .tar.gz and the rest. The bsdtar man page also rules out anything that isn’t a regular file, such as a pipe.
| Command | What it does |
|---|---|
tar -rf proj.tar proj/NOTES.md | Add a file to the end of an existing archive |
tar -uf proj.tar proj | Append copies of files that are newer than the archived ones |
-u doesn’t replace anything. It adds a second copy, so the archive only grows:
-rw-r--r-- box/box 7 2026-10-25 09:00 proj/README.md -rw-r--r-- box/box 6 2026-10-25 10:54 proj/NOTES.md -rw-r--r-- box/box 10 2026-10-25 10:54 proj/README.md
That’s tar -tvf proj.tar | grep -E "README|NOTES" after one -r and one -u. Extracting writes each copy in turn, so the last one wins.
| Command | What it does |
|---|---|
cp proj.tar trimmed.tar && tar --delete -f trimmed.tar proj/logs | REWRITES ARCHIVE in place, GNU only: remove members from an archive. Work on a copy |
On a compressed archive, GNU tar refuses with tar: Cannot update compressed archives and bsdtar with bsdtar: Cannot append to compressed archive. bsdtar has no --delete (bsdtar: Option --delete is not supported). For a backup that changes, making a fresh archive is simpler than -u.
pipes, stdin, and ssh
-f - reads the archive from stdin or writes it to stdout, so tar can feed another tar, a compressor or ssh without a temporary file.
| Command | What it does |
|---|---|
mkdir copy && tar -C proj -cf - . | tar -C copy -xpf - | OVERWRITES files in copy/: copy a tree with permissions, through a pipe |
tar -czf - proj | ssh host 'mkdir -p /srv/x && tar -xzf - -C /srv/x' | OVERWRITES files under /srv/x on host: push a directory to another machine |
ssh host 'tar -C /etc -czf - nginx' > nginx-etc.tar.gz tar -tzf nginx-etc.tar.gz | REPLACES ARCHIVE: pull a remote directory into a local archive, then check it reads |
find proj -name '*.c' -print0 | tar --null -cf cfiles.tar -T - | Archive only the files another command lists, safe for names with spaces or newlines (GNU and bsdtar) |
GNU tar doesn’t detect compression on stdin, so cat proj.tar.gz | tar -tf - stops with tar: Archive is compressed. Use -z option. cat proj.tar.gz | tar -tzf - works. bsdtar detected gzip and zstd on stdin without a flag.
The ssh rows ran over a real ssh hop through a bastion in a lab: GNU tar 1.34 and OpenSSH 9.2p1 on Debian 12 (aarch64), on both the client and the remote side, as an unprivileged user. /tmp on the remote side stood in for /srv, and the pull was run with /etc/apt because nginx wasn’t installed. Pitfalls from that run:
- A missing remote
-Cdirectory fails only on the remote side. The remote tar printedtar: /tmp/nope: Cannot open: No such file or directory, while the local tar exited 0 for a small tree; with a larger one it also fails, withWrote only … bytes. That second case was reproduced on the box with a 31 MB tree andsh -cin place of ssh:tar: -: Wrote only 8192 of 10240 bytes,PIPESTATUS2 2. Themkdir -pin the push row fixes it. - In bash,
echo "${PIPESTATUS[@]}"straight after the pipe shows both sides' exit codes: the local tar’s, then ssh’s, which passes on the remote tar’s. For the missing directory it was0 2. - Never use
ssh -n(-fimplies-n) when piping into ssh. ssh then sends nothing, and the remote tar stopped withgzip: stdin: unexpected end of file(PIPESTATUS0 2). - Don’t force a terminal. With
-tt, or with-tfrom an interactive shell on the pull, the remote tar refuses withRefusing to write archive contents to terminaland the local tar seesgzip: stdin: not in gzip format. In the lab,ssh -ttgave that gzip message andPIPESTATUS2 2. The refusal itself was reproduced on the box by giving GNU tar 1.35 a terminal withscript; bsdtar 3.7.4 didn’t refuse. The interactive-tcase wasn’t run. From a script, plain-tonly warnedPseudo-terminal will not be allocated because stdin is not a terminal.and the archive came through. - After a pull to a file, check it with
tar -tzf file. The shell creates the file even when the remote side fails. /srvand/etc/nginxnormally need root on the remote side, and extracting as root brings back the archived owners and setuid bits (see the next section).- Anything the remote shell’s startup files print to stdout lands in the stream and corrupts it (reproduced locally, not over the ssh hop).
- Inside double quotes,
$VARIABLESexpand on your machine before ssh sends the command. Single quotes, as above, send them to the remote shell.
For copying the same tree again and again, rsync only sends what changed.
permissions and ownership
What happens to owners and modes depends on who runs the extract.
- As a normal user: files belong to you, and your umask is subtracted from each file’s mode.
-pkeeps the archived modes. You can’t give files to another owner. - As root: GNU tar and bsdtar both restore the archived owner, group and mode by default. umask is ignored, and setuid and setgid come back.
The archived file here is mode 666, owned by uid 1234. With umask 022, ls -ln showed:
| Command | What it does |
|---|---|
tar -xf perm.tar -C p1 output -rw-r--r-- 1 1000 1000 2 Oct 25 09:00 shared.txt | OVERWRITES: as a normal user, owner becomes you, umask applied |
tar -xpf perm.tar -C p2 output -rw-rw-rw- 1 1000 1000 2 Oct 25 09:00 shared.txt | OVERWRITES: as a normal user, keeping the archived modes |
sudo tar -xf perm.tar -C p3 output -rw-rw-rw- 1 1234 1234 2 Oct 25 09:00 shared.txt | OVERWRITES: as root, the archived owner and mode come back |
sudo tar --no-same-owner --no-same-permissions -xf perm.tar -C p4 output -rw-r--r-- 1 0 0 2 Oct 25 09:00 shared.txt | OVERWRITES: as root, files owned by root, special bits dropped (GNU needs both flags) |
--no-same-owner alone keeps setuid and setgid, so a setuid member becomes setuid-root. bsdtar -o removes those bits but kept the other mode bits (-rw-rw-rw-, owned by root).
That’s the root caveat. A member stored as -rwsr-sr-x (setuid and setgid), owned by uid 1234, came out of the test like this:
-rwsr-sr-x 1 1234 1234 2 Oct 25 09:00 tool
- That’s
sudo tar -xfandsudo bsdtar -xf, even with umask 077.sudo tar --no-same-owner -xfgave-rwsr-sr-x 1 0 0. Adding--no-same-permissionsgave-rwxr-xr-x 1 0 0, andsudo bsdtar -xofgave the same. - As a normal user without
-p, both tars dropped the bits. GNUtar -xpfkept them on a file you now own. bsdtar-xpfdropped them. - When the owner can’t be restored, GNU 1.35 doesn’t clear the bits. As a normal user,
tar --same-owner -xpfprintedCannot change ownership to uid 1234, gid 1234: Operation not permitted, exited 2, and still left-rwsr-sr-x. bsdtar printedsu/tool: Can't restore SUID bitand left-rwxr-xr-x.
Extract archives you didn’t make as a normal user, without -p.
| Command | What it does |
|---|---|
tar -cf release.tar --owner=0 --group=0 --numeric-owner proj | REPLACES ARCHIVE: store files as owned by root (uid and gid 0), whoever runs it (GNU tar) |
bsdtar -cf release.tar --uid 0 --gid 0 --uname root --gname root proj | REPLACES ARCHIVE: the same with bsdtar |
Extended attributes: bsdtar archives them by default. A normal user gets them back only with -p, and root gets them by default. GNU tar needs --xattrs on both create and extract. GNU read bsdtar’s xattrs with --xattrs but warned Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.user.note'. GNU also has --acls and --selinux (not run here).
sparse files
| Command | What it does |
|---|---|
tar -cSf disk.tar disk.img | REPLACES ARCHIVE, GNU: store the holes in sparse files instead of writing out the zeros |
In the test, a 100 MB sparse file holding one 4-byte write (4 KB on disk) made a 104,867,840-byte archive with plain tar -cf and a 10,240-byte one with -S. bsdtar handled the holes without a flag (7,680 bytes). Both restored the file with its holes and identical contents. Extracting the plain GNU archive wrote all 100 MB to disk.
stay on one filesystem
| Command | What it does |
|---|---|
tar -cf /mnt/backup/home.tar --one-file-system /home | REPLACES ARCHIVE: archive /home but don’t descend into anything mounted inside it |
In the test, with a tmpfs mounted inside the tree, GNU tar 1.35 and bsdtar 3.7.4 both kept the empty mount-point directory and left out what was mounted on it. The /home example wasn’t run.
verify and compare
| Command | What it does |
|---|---|
tar -tzf proj.tar.gz > /dev/null && echo archive reads OK gzip -t proj.tar.gz && sha256sum proj.tar.gz > proj.tar.gz.sha256 sha256sum -c proj.tar.gz.sha256 | Read the whole archive, test the gzip layer, and keep a checksum to check after copying |
xz -t, zstd -t and bzip2 -t test the other formats. On a truncated archive, GNU tar and bsdtar both exited nonzero.
| Command | What it does |
|---|---|
tar -df proj.taroutput tar: proj/src/util.c: Warning: Cannot stat: No such file or directory proj/README.md: Mod time differs proj/README.md: Size differs proj/run.sh: Mode differs | GNU only: compare the archive with the files on disk (run from the directory you archived from) |
That’s after editing one file, changing one file’s mode and moving another away. With no differences, tar -df prints nothing and exits 0. It reads compressed archives too (tar -dzf proj.tar.gz), and --compare is the long form.
| Command | What it does |
|---|---|
tar -cvWf proj.tar proj | GNU only: read the archive back after writing it (uncompressed archives only) |
With -v, -W prints a Verify proj/... line for each member. -W with -z stops with tar: Cannot verify compressed archives.
| Command | What it does |
|---|---|
mkdir cmp && bsdtar -xf proj.tar -C cmp && diff -r proj cmp/proj && echo identical | bsdtar has no -d: extract to a scratch directory and diff instead (works with GNU too) |
tarbombs and path traversal
A tarbomb is an archive with no top directory, so it spills its files into wherever you extract it. A hostile archive can go further and hold member names that point outside the directory. Look before you extract.
| Command | What it does |
|---|---|
tar -tf bomb.tar | cut -d/ -f1 | sort -u output a.txt b.txt c.txt | What top-level names will this create? One name means one directory |
mkdir bomb && tar -xf bomb.tar -C bomb | Contain it: extract into a new, empty directory |
The hostile test archive held an absolute name (/tmp/tl-tar/pwn-abs.txt), two names with .. (../pwn-dotdot.txt and ok/../../pwn-mid.txt), a symlink link -> /tmp/tl-tar, and a file link/pwn-link.txt written through it. Extracting it into an empty directory:
- GNU tar 1.35 wrote the absolute name as
./tmp/tl-tar/pwn-abs.txt, inside the directory. It refused both..names (Member name contains '..'), refused to write through the symlink (link/pwn-link.txt: Cannot open: Not a directory), and exited 2. - bsdtar 3.7.4 also wrote the absolute name inside the directory. It refused both
..names (Path contains '..'), refused the symlink (Cannot extract through symlink link/pwn-link.txt), and exited 1.
That holds only for an empty directory. GNU tar 1.35 follows a symlink that’s already there, including one left by an earlier archive. In the test, a directory holding link -> /tmp/tl-tar/outside was given an archive with link/pwn.txt, and GNU tar wrote pwn.txt outside the directory, with no message and exit status 0. The same happened when one archive created the symlink and a second archive wrote through it. -k, --skip-old-files, --no-overwrite-dir and --unlink-first didn’t stop it. When the archive also had a link/ directory entry, plain GNU tar replaced the symlink, but with -k or --keep-directory-symlink the write still went outside. bsdtar never wrote outside: it refused a file under the symlink (Cannot extract through symlink, exit status 1), and when the archive had a link/ directory entry it replaced the symlink with a directory. Its -U also replaced the symlink. GNU tar after 1.35 fixes this (NEWS for 1.35.90), and the online GNU Security page describes the fixed behaviour. Use a fresh, empty directory for every untrusted archive.
| Command | What it does |
|---|---|
tar -xPf trusted.tar | DANGEROUS, OVERWRITES ANYWHERE YOU CAN WRITE: -P keeps absolute names, .. and symlinks. Trusted archives only |
With -P, GNU tar wrote all four files outside the extraction directory and exited 0. bsdtar -P wrote the absolute and .. members outside it too, also with exit status 0.
GNU tar also resets an existing directory’s mode to the archived one: a 700 directory became 755. bsdtar did that only with -p or as root. GNU --no-overwrite-dir stops it. The bsdtar man page recommends listing with -tf first, -k to keep existing files, and not extracting as root.
GNU tar vs bsdtar
Each line was run with GNU tar 1.35 and bsdtar 3.7.4 on Linux, unless it says otherwise. Differences already covered above (patterns, compressed stdin, -d, --delete, -k, excludes, setuid, symlinks) aren’t repeated.
- Verify after writing: GNU has
-W. bsdtar doesn’t:bsdtar -cWf w.tar projfailed withAmbiguous option -W f (matches --format and --files-from). - Rename members on the way in or out: GNU
--transform 's,^proj,proj-1.2,'. bsdtar-s ',^proj,proj-1.2,'. Both gaveproj-1.2/README.md. - Other formats: bsdtar lists and extracts zip files (
bsdtar -tf proj.zip) and creates them (bsdtar -caf proj.zip proj). GNU tar saysThis does not look like a tar archive. - Default format: GNU tar on Debian writes the
gnuformat (tar --show-defaultsprinted--format=gnu). The bsdtar man page says it writes restricted pax. Each read the other’s archives in the test. - Extended attributes and ACLs: bsdtar archives xattrs by default. GNU needs
--xattrson create and extract, and--aclsfor ACLs. The bsdtar man page says ACLs are archived by default, except on Mac OS X. - Sparse files: GNU needs
-S. bsdtar handled them by default. - macOS metadata: the bsdtar man page says
--mac-metadatais Mac OS X only and the default when creating, so archives made on a Mac can carry extended attributes and ACLs in AppleDouble form, which show up as._files elsewhere.--no-mac-metadataalone isn’t enough. For an archive with no._files, usetar --no-mac-metadata --no-xattrs -cf x.tar dir(per the bsdtar man page and libarchive issue 2486), orCOPYFILE_DISABLE=1 tar --no-xattrs -cf x.tar dir(the variable is read by bsdtar on macOS, per libarchive’s bsdtar.c and Apple’s copyfile.h). Neither was run on macOS. Checkman taron your Mac, because its bsdtar version may differ from 3.7.4.
gotchas
-ftakes the next word as the archive name. In the test, GNUtar -cfz x.tar projwrote an uncompressed archive calledzand complainedx.tar: Cannot stat. Keepflast in a bundle like-czf.tar -xwrites paths relative to the current directory, or-C. Checkpwdfirst, especially as root.- Member names have to match what
tar -tfprints,./included, in GNU tar.
related on terminal-life
sources
Checked against the GNU tar manual on gnu.org (the edition online is for 1.35.90, the development version after 1.35), the GNU tar NEWS file, and the bsdtar man page from libarchive 3.7.4 (tar/bsdtar.1, dated April 23, 2024). On another version, check man tar or info tar on your own machine.
Tested with GNU tar 1.35 (Debian package 1.35+dfsg-3.1) and bsdtar 3.7.4 (libarchive-tools 3.7.4-4+deb13u1) on Debian GNU/Linux 13 (trixie), Linux 6.12, with gzip 1.13, bzip2 1.0.8, xz 5.8.1 and zstd 1.5.7. The ssh rows also ran over a real ssh hop with GNU tar 1.34 and OpenSSH 9.2p1 on Debian 12 (aarch64) on both ends. Not run on macOS.
Sources:
Full source links: terminal-life.com/cheatsheets/tar/#sources
terminal-life.com/cheatsheets/tar/ · checked against the GNU tar manual and the bsdtar 3.7.4 man page