0

I want to find all .c files in current directory and subdirectories and tar them. I try to use the following way to achieve this goal but when i unzip files, the files in different folders. I don't want to include directory when I tar the file.

The script should exclude all other files and should not maintain the directory structure for these .c files.

find . -name '*.c' | xargs tar -rf allcfiles.tar 

enter image description here

.

3 Answers 3

3

If you have GNUtar (which is common on Linux) then you can use the --transform option.

For example, with your current command we can see there's directories:

$ find . -name '*.c' | xargs tar -rf allcfiles.tar
$ tar tf allcfiles.tar                            
./b.c
./d/e.c
./a.c

With a transform we can avoid this:

$ find . -name '*.c' | xargs tar --transform='s!.*/!!' -rf allcfiles.tar
$ tar tf allcfiles.tar                                                  
b.c
e.c
a.c

The expression inside the --transform is a simple sed expression. This one just strips off all directory components.

5
  • With a real TAR implementation, this gives error messages because the archive does not exist at the beginning. The original UNIX TAR does not deal with this at all, because it never creates an archive in replace mode. star warns because the archive at the beginning does not have a correct EOF marker. I recommend a modern tar like star with built in find and with pax like path substitution and not to use the replace mode.
    – schily
    Jan 23, 2020 at 9:41
  • thanks for your help. I am using macos. I tried ur answer but it does not work
    – chen Crush
    Jan 23, 2020 at 13:30
  • If you're using macOS then you might want to change the tags; you added "linux" as a tag, and so I gave a Linux answer... Jan 23, 2020 at 15:30
  • It works on linux. Thanks a lot. I need to run script on linux not macos. Sorry for not beeing clear.
    – chen Crush
    Jan 23, 2020 at 20:10
  • Since we are going to rely on GNU features, it's probably worth mentioning the options to handle file names safely - find ... -print0 and xargs -0. (Sure, newlines in real-world file names are extremely unlikely, but...).
    – fra-san
    Jan 23, 2020 at 22:50
3

If your find implementation supports the -execdir option, you can tar the files without their directories like this:

find . -name '*.c' -type f -execdir tar rf $PWD/mytar.tar {} +

Just make sure the path to the tar file is an absolute path.

0
0

Here is a method that works using only POSIX compliant commands:

find . -name '*.c' | pax -w  -s ',.*/,,' > allcfiles.tar

If you like to use tar rf archive ..., you need to start with a correct empty archive at the beginning, since a real tar does not create the archive when in replace mode. To achieve this, you could first run this command to create an empty TAR archive:

printf "\000"| dd ibs=10k conv=sync > allcfiles.tar 

By the way, I prefer this command:

star cf allcfiles.tar -s ',*/,,' -find . -name '*.c'

since this is the fastest method because star uses libfind and this needs to call stat() only once per file as the stat data from libfind is used by star to set up the file meta data in the archive.

3
  • thanks for your help. I am using macos. I tried ur answer but it does not work. I wonder if macos cannot do this at all.
    – chen Crush
    Jan 23, 2020 at 13:29
  • Which command did you try and why did it fail? Since MacOS claims to be POSIX compliant, it needs to work with my POSIX compliant command.
    – schily
    Jan 23, 2020 at 13:32
  • @chenCrush: Given that the command works on FreeBSD and that MacOS has a FreeBSD userland, it is highly improbable that the command fails on MacOS.
    – schily
    Jan 24, 2020 at 9:53

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.