16

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?

Shafiul
  • 278
  • 1
  • 2
  • 6

3 Answers3

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

slhck
  • 235,242
4

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.

Giacomo1968
  • 58,727
shaheen g
  • 161
  • 3
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 -
noraj
  • 458
  • 1
  • 5
  • 16