0

For example, suppose A/B/C is the main directory. Under the C directory, I will have sub-directories and files. But I want to tar only the directories with its own name as below

If the directories under c are Test1 Test2 - I want them as Test1.tar Test2.tar

This is on a Linux machine.

  • 2
    And how do you want them to be added to the archive? Should they keep the same structure? Should all directories be brought to the same level? Please edit your question and show us i) a detailed example of the current directory structure (ideally, use the command tree) and ii) what you want to happen when you un-tar your tar file in a new location. – terdon Nov 29 '18 at 11:48
  • For example: do you want to tar the directories A and B? Do you want to tar the files in C? Or do want to tar only the content of Test1 and Test2? – sudodus Nov 29 '18 at 12:15
1

You can tell tar not to recurse into its arguments, and then use find to provide it with every directory as an argument. So, something like this:

find . -type d -print0 | xargs -0 tar --no-recursion -cf your_tree.tar

The -print0 and -0 are to avoid problems with directories that have spaces and other special characters in their name.

As pointed out in comments below, if you have a lot of directories then the command line would become too big and tar would end up being invoked multiple times. In that case you could instead read the arguments using --files-from:

find . -type d -print0 | tar --null --no-recursion --files-from - -cf your_tree.tar

Edit:

The above was written before the OP clarified that they wanted a set of tar files in the top level directory. I think the above technique can still be used to achieve this. For example:

$ mkdir -vp tree/a/b/c tree/foo/bar/baz                                                                                 
mkdir: created directory ‘tree’
mkdir: created directory ‘tree/a’
mkdir: created directory ‘tree/a/b’
mkdir: created directory ‘tree/a/b/c’
mkdir: created directory ‘tree/foo’
mkdir: created directory ‘tree/foo/bar’
mkdir: created directory ‘tree/foo/bar/baz’
$ touch tree/foo/an_unwanted_file
$ cd tree
/var/tmp/tree
$ for dir in $(find . -maxdepth 1 -type d); do if [ "$dir" != "." ]; then find "$dir" -type d -print0 | tar --null --no-recursion --files-from - -cvf "${dir}.tar"; fi; done
./a/
./a/b/
./a/b/c/
./foo/
./foo/bar/
./foo/bar/baz/
$ tar tvf foo.tar                                                                                                       
drwxr-xr-x andy/andy         0 2018-11-29 12:30 ./foo/
drwxr-xr-x andy/andy         0 2018-11-29 12:30 ./foo/bar/
drwxr-xr-x andy/andy         0 2018-11-29 12:30 ./foo/bar/baz/
$ tree
.
├── a
│   └── b
│       └── c
├── a.tar
├── foo
│   ├── an_unwanted_file
│   └── bar
│       └── baz
└── foo.tar
  • 1
    Note that tar may be invoked several times when run like this through xargs. Each new invocation would truncate the archive. – Kusalananda Nov 29 '18 at 11:55
  • Hmm, I think that would only happen if you had many many thousands of directories wouldn't it? But yeah I can see how that might happen. I think you can work around that one by using --files-from - instead. I'll edit, thanks. – grifferz Nov 29 '18 at 12:00
  • Also, if a directory a/b/c is added, it would be added again when the a/b directory was processed... I think (haven't tested). – Kusalananda Nov 29 '18 at 12:16
  • Thanks Grifferz. But the names of folders should be dynamic as in question's example. This will not work for me. – Bhavya Nov 29 '18 at 12:18
  • 1
    @Bhavya the question's example is very unclear. Once again: please edit your question and include an actual directory structure and then show what you would like to get from the tar file. Use tree as shown in this answer. – terdon Nov 29 '18 at 12:52
1
for dir in A/B/C/*/; do
    name=$(basename "$dir")
    tar -cv -f "$name.tar" -C A/B/C "$name"
done

This would create an archive for each individual (non-hidden) subdirectory under A/B/C. The archives would be created in the current directory.

The -C option makes tar set the working directory for the following files ($name).

You could use -C "$(dirname "$dir")" in place of -C A/B/C for slightly more generic code.


To create the archives under the C subdirectory

( cd A/B/C &&
  for dir in */; do
      tar -cv -f "${dir%/}.tar" "$dir"
  done )

The subshell around the whole command prevents the working directory from being changed in the rest of the shell/script, and ${dir%/} removes the trailing slash at the end of the value in $dir.

Unfortunately, the -C option does not affect the working directory for the archive file specified by -f, otherwise we could just have moved the -C bit before the -f option.

Alternatively, as a variant of the first loop:

for dir in A/B/C/*/; do
    name=$( basename "$dir" )
    ( cd "$( dirname "$dir" )" && tar -cv -f "$name.tar" "$name" )
done
-1

I recommend to use star (I am the author of starwhich is the oldest free tar implementation):

star cf file.tar -find . -type d

This works for any number of names in the tar file since star uses libfind-

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.