15

I'm using this command to archive a directory named g from Java code:

tar czf /a/b/c.tar.gz /e/f/g

When the tar file c.tar.gz is created, I find an entire path e/f/g then all files of the g folder inside it. But I only want to see files under the folder g in the compressed archive when I open it. How do I remove the folders /e/f/ in the .tar.gz file?

3 Answers 3

26
tar -czf /a/b/c.tar.gz -C /e/f/g .

The -C option makes tar change the working directory, so you only need to add ..

See: Changing the Working Directory – GNU tar manual

1
3

This question is from a while ago, but I still could not find the answer for myself easily for adding files and folders with specific search criteria with relative paths.

The following covers a broader topic than what has been asked. So, I am writing up the solution I came up following my research.

Let's assume your $input_dir variable points to your directory of interest and you are looking to tar and compress (using gzip) all your *.txt files into ~/my_txt.tar.gz. To create a gzipped tarball with no path stored in the tar (relative path), use the following:

find "$input_dir" -maxdepth 1 -type f -name "*.txt" -printf "%P\0" | tar --null --create --remove-files --gzip --file="$HOME/my_txt.tar.gz" --directory="$input_dir" --files-from=-

Let's break it down:

  • "$input_dir": The starting-point directory. Change it to whatever you like.
  • maxdepth 1: only looks in the root of that directory. You can remove or modify it if you want to search all or different levels.
  • -type f: search only for files
  • -name "*.txt": matching the *.txt criteria
  • -printf "%P": output the Relative Path (man page: "File's name with the name of the starting-point under which it was found removed").
  • -printf "%P\0": null terminate the relative path outputs
  • | tar: pipe the outputs to the next command which is tar here
  • --null: instructs subsequent --files-from option to read null-terminated names. Remember that we asked find to create null terminated (\0) outputs instead of regular \n terminated outputs. This is to cover all possible filenames with spaces or other special characters.
  • --create: create the tar file. Equal to -c.
  • --remove-files: I use this option to remove the files after they are added to the tarball. You can drop it.
  • --gzip: gzip the tarball. Equal to -z.
  • --file="$HOME/my_txt.tar.gz": The output gzipped tarball file. Equal to -f "$HOME/my_txt.tar.gz"
  • --directory="$input_dir": This means that tar now changes to this directory. Now it will look for the filenames that is passed on in this directory (remember that we have made the filenames' relative path to this folder). Equal to -C "$input_dir".
  • --files-from=/dev/stdin: Its general form is --files-from=FILE. This option with the --null option instructs tar that the names in FILE are separated by ASCII NULL character, instead of the Line Feed (\n). We also say that the FILE is stdin (piped from find directly to tar rather than reading from a FILE on disk). Equal to -T -.

Some of the above can be changed to one character options and can be combined.

find "$input_dir" -maxdepth 1 -type f -name "*.txt" -printf "%P\0" | tar --null --remove-files -czf "$HOME/my_txt.tar.gz" -C "$input_dir" -T -

You can check the file list using -t or --list option:

tar -tf "$HOME/my_txt.tar.gz"

Now to extract the files to $output_dir directory (which exists), use this:

tar -xvzf "$HOME/my_txt.tar.gz" -C "$output_dir"

The v option is verbose and you can also add it during tarball creation.

2
  • Thanks, because tar -czf /a/b/c.tar.gz -C /e/f/g . was working but including all files in the input dir, tar -czf /a/b/c.tar.gz -C /e/f/g /e/f/g/*.txt works to select only txt files but is storing the relative path and tar -czf /a/b/c.tar.gz -C /e/f/g *.json or tar -czf /a/b/c.tar.gz -C /e/f/g ./*.json don't work trying to expand the current working directory instead of taking -C. So using find piped to tar was the only way to make it right.
    – noraj
    Aug 15, 2023 at 15:32
  • However, the null byte trick make it impossible to include this command in many programming languages (error similar to: string contains null byte).
    – noraj
    Aug 15, 2023 at 15:38
0

slhck answer does not allow to filter which files we want and includes the whole directory, and shell globbing won't work with this directory option (see this issue described here: How to make tar globbing work with the 'change directory' option).

shaheen g answer is great but null bytes prevented me to use the command in a programming language because null byte are forbidden in a string. So I adapted it to work without null byte when you don't need to handle file names with whitespace, answer here.

tar -czf /a/b/c.tar.gz -C /e/f/g $(find /e/f/g -maxdepth 1 -type f -name "*.txt" -printf "%f\n")

or

find /e/f/g -maxdepth 1 -type f -name "*.txt" -printf "%f\n" | tar -czf /a/b/c.tar.gz -C /e/f/g -T -

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .