How to compress only symlink from directory as tar.gz?

I need linux command to compress only symlink from some directory such as this screnshot.
I do not need to compress as name. like this

tar -czf /tmp/test.tar.gz cars movies plugin 2.txt 10.txt

Because the symlink names are variable and not fixed
enter image description here

Asked By: RAED

||

On the command line, one solves complex tasks by combining multiple commands. If we know there are no spaces and special characters in the names of the symlinks, one can simply use find with command substitution:

tar -czf /tmp/test.tar.gz `find -maxdepth 1 -type l`

This won’t work for example with spaces or semicolons in a name. In this case, a simple solution is to write the list to a temporary file:

TMPLIST=`mktemp`
find -maxdepth 1 -type l -print0 > $TMPLIST
tar -czf /tmp/test.tar.gz --null --files-from $TMPLIST
rm $TMPLIST
Answered By: Joachim Wagner

With zsh, you can use the @ glob qualifier to restrict glob expansions to files of type symlink:

tar -czf file.tar.gz -- *(@)

To also include hidden ones, add the D (for Dot-file) qualifier:

tar -czf file.tar.gz -- *(D@)

In other shells, you could use find to find the files of type symlink and pass them to tar:

find . ! -name . -prune -type l -exec tar -zcf file.tar.gz {} +

But note some differences compared to the zsh approach:

  • the hidden files are included and it takes some:

    LC_ALL=C find . ! -name . -prune ! -name '.*' -type l -exec tar -zcf file.tar.gz {} +
    

    to exclude them reliably.

  • the list of file is not sorted.

  • a ./ prefix is added to the archive members (and it’s why we don’t need the --).

  • if there are a lot of matching files, find may end up calling tar several times which would mean file.tar.gz would only include the files from the last run. (in those cases, with the zsh approach, you may end-up getting a argument list too longer error instead).

With the GNU implementations of find, sort and tar, and ifne from moreutils, you can address those by doing:

LC_ALL=C find . ! -name . -prune ! -name '.*' -type l -printf '%P' |
  sort -z |
  ifne tar -zcf file.tar.gz --null -T -

Where:

  • we use -printf '%P' to print the paths of the files relative to the starting directory (.), so for instance it prints link instead of ./link. It’s NUL delimited as 0 is the only byte value that can’t occur in a file path.
  • sort -z sorts those NUL-delimited records lexically as per the locale’s collation order like for zsh globs.
  • we pass that list to tar via a pipe on its stdin rather than as arguments to avoid the system’s limit on the size of the arguments.
  • ifne is needed to cover the case where there’s no file, in which case if find that without it GNU tar 1.34 at least seems to be creating a mostly-sparse 10KiB file.tar.gz filled with zeros.

In any case, remember that one shouldn’t create files with fixed name in world-writable directories such as /tmp as that’s a security risk.

Answered By: Stéphane Chazelas
Categories: Answers Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.