Extract tarball into the same directory - bash

I have a hierarchy of folders, which contain a lot of tarballs. I need to write a script which recursively goes to each directory, extract the tarball in the corresponding directory.
I tried
find ./ -name "*.tar.gz" -exec /bin/tar -zxvf {} \;
The code executed with all the tarballs extracted to the pwd, not in the corresponding directory.
Please assist me on this if possible. Thanks :)

You can use find like this:
find . -name "*.tar.gz" -exec bash -c 'd=$(dirname "{}") && b=$(basename "{}") && cd "$d" && tar zxvf "$b"' \;
EDIT A shorter version of above find command will be:
find . -name "*.tar.gz" -execdir tar zxvf "{}" \;

Related

How to remove all subdirectories? (unix shell scripting)

I have a directory called "cdrs-roaming". Everyday I receive one or more .zip files and unzip them with this:
#!/bin/bash
for i in *.zip
do
j=${i//\.zip/}
mkdir $j
cd $j
unzip ../$i
cd -
done
Then I have for example:
"example1.zip" and "example1"; "example2.zip" and "example2"
I'm removing all zip files (in this case: "example1.zip" and "example2.zip") with this:
#! /bin/bash
find /dados/cdrs-roaming/*.zip -mtime +1 -exec rm {} \;
So I want to remove the directories (or folders - I really don't know the difference) "example1" and "example2". I've tried this:
#! /bin/bash
find /dados/cdrs-roaming/ -type d -mtime +1 -exec rm -rf {} \;
But it also removes "cdrs-roaming". I've also tried to use:
find /cdrs-roaming/ -type d -mtime +1 -exec rm -rf {} \;
But it returns: find: ‘/cdrs-roaming/’: No such file or directory
Any idea for doing this? I need to delete only the directories within "cdrs-roaming" but I can't remove anything else inside it (my .sh files are inside of it)
Since you are using bash, how about
rm -rf /dados/cdrs-roaming/*/
The final slash ensures that bash only expands the pattern to directories.
Use -mindepth 1 option:
find /dados/cdrs-roaming/ -mindepth 1 -type d -mtime +1 -exec rm -rf {} \;

Collect jars into a tar without directory

I have a large project that creates a large number of jars in a path similar to project/subproject/target/subproject.jar. I want to make a command to collect all the jars into one compressed tar, but without the directories. The command I have come up with so far is: find project -name \*.jar -exec tar -rvf Collectors.tar.gz -C $(dirname {}) $(basename {}) \; but this isn't quite working as I am intending, the directories are still there.
Does anyone have any ideas for how to resolve this issue?
Your command is quite close, but the problem is that Bash is executing $(dirname {}) and $(basename {}) before executing find; so your command expands to this:
find project -name \*.jar -exec tar -rvf Collectors.tar.gz -C . {} \;
where the -C . is a no-op and the {} just expands to the full relative directory+filename.
One general-purpose way to fix this sort of thing is to wrap up the argument to -exec in a Bash one-liner, so you invoke Bash for each individual file, and let it execute the dirname and basename at the right time:
find project -name \*.jar -exec bash -c 'tar -rvf Collectors.tar.gz -C "$(dirname "$1")" "$(basename "$1")"' '' '{}' \;
In your specific case, however, I'd point you to find's -execdir action, which is the same as -exec except that it cd's into the file's directory first. So you can simply write:
find project -name '*.jar' -execdir tar -rvf "$PWD/Collectors.tar.gz" '{}' \;
(Note that $PWD part, which is to make sure that you write to the Collectors.tar.gz in the current directory, rather than in the directory that find -execdir will cd into.)

Unzip files in subdirectories bash

I have a directory called test1 which contains multiple directories. In each directory test1/*/, there is a *.gz file that I want to unzip. I tried writing this code but it doesn't work, any help would be appreciated.
for folder in test1/*/; do find . -name "*.gz" | while read filename; do gunzip -d $filename;done ;done
gunzip test1/*/*.gz
gunzip will extract the file in the directory it is in.
You can just do that using find:
cd test1
find . -name "*.gz" -execdir tar xzf '{}' \;
Remember that unzip command only works with .zip files.
PS: If .gz files have not been created using tar czf then use gunzip instead:
find . -name "*.gz" -execdir gunzip '{}' \;
I edited my command and it works now:
find ${path} -name "*.gz" | while read filename; do gunzip -d $filename; done

How to use the pwd as a filename

I need to go through a whole set of subdirectories, and each time it finds a subdirectory named 0, it has to go inside it. Once there, I need to execute a tar command to compact some files.
I tried the following
find . -type d -name "0" -exec sh -c '(cd {} && tar -cvf filename.tar ../PARFILE RS* && cp filename.tar ~/home/directoryForTransfer/)' ';'
which seems to work. However, because this is done in many directories named 0, it will always overwrite the previous filename.tar one (and I lose the info about where it was created).
One way to solve this would be to use the $pwd as the filename (+.tar at the end).
I tried double ticks, backticks, etc, but I never manage to get the correct filename.
"$PWD"".tar", `$PWD.tar`, etc
Any idea? Any other way is ok, as long as I can link the name of the file with the directory it was created.
I'd need this to transfer the directoryToTransfer easily from the cluster to my home computer.
You can try "${PWD//\//_}.tar". However you have to use bash -c instead of sh -c.
Edit:
So now your code should look like this:
find . -type d -name "0" -exec bash -c 'cd {} && tar -cvf filename.tar ../PARFILE RS* && cp filename.tar ~/home/directoryForTransfer/"${PWD//\//_}.tar"' ';'
I personally don't really like the using -exec flag for find as it makes the code less readable and also forks a new process for each file. I would do it like this, which should work unless a filename somewhere contains a newline (which is very unlikely).
while read dir; do
cd {} && tar -cvf filename.tar ../PARFILE RS* && cp filename.tar ~/home/directoryForTransfer/"${PWD//\//_}.tar"
done < <(find . -type d -name "0")
But this is just my personal preference. The -exec variant should work too.
You can use -execdir option in find to descend in each found directory and then run the tar command to greatly simplify your tar command:
find . -type d -name "0" -execdir tar -cvf filename.tar RS* \;
If you want tar file to be created in ~/home/directoryForTransfer/ then use:
find . -type d -name "0" -execdir tar -cvf ~/home/directoryForTransfer/filename.tar RS* \;

Recursively unzip files and then delete original file, leaving unzipped files in place from shell

I've so far figured out how to use find to recursively unzip all the files:
find . -depth -name `*.zip` -exec /usr/bin/unzip -n {} \;
But, I can't figure out how to remove the zip files one at a time after the extraction. Adding rm *.zip in an -a -exec ends up deleting most of the zip files in each directory before they are extracted. Piping through a script containing the rm command (with -i enabled for testing) causes find to not find any *.zips (or at least that's what it complains). There is, of course, whitespace in many of the filenames but at this point syntaxing in a sed command to add _'s is a bit beyond me. Thank for your help!
have you tried:
find . -depth -name '*.zip' -exec /usr/bin/unzip -n {} \; -exec rm {} \;
or
find . -depth -name '*.zip' -exec /usr/bin/unzip -n {} \; -delete
or running a second find after the unzip one
find . -depth -name '*.zip' -exec rm {} \;
thx for the 2nd command with -delete! helped me a lot..
just 2 (maybe helpful) remarks from my side:
-had to use '.zip' instead of `.zip` on my debian system
-use -execdir instead of -exec > this will extract each zip file within its current folder, otherwise you end up with all extracted content in the dir you invoked the find cmd.
find . -depth -name '*.zip' -execdir /usr/bin/unzip -n {} \; -delete
THX & Regards,
Nord
As mentioned above, this should work.
find . -depth -name '*.zip' -execdir unzip -n {} \; -delete
However, note two things:
The -n option instructs unzip to not overwrite existing files. You may not know if the zip files differ from the similarly named target files. Even so, the -delete will remove the zip file.
If unzip can't unzip the file--say because of an error--it might still delete it. The command will certainly remove it if -exec rm {} \; is used in place of -delete.
A safer solution might be to move the files following the unzip to a separate directory that you can trash when you're sure you have extracted all the files successfully.
Unzip archives in subdir based on the file name (../file.zip -> ../file/..):
for F in $(find . -depth -name *.zip); do unzip "$F" -d "${F%.*}/" && rm "$F"; done
I have a directory filling up with zipped csv files. External processes are writing new zipped files to it often. I wish to bulk unzip and remove the originals as you do.
To do that I use:
unzip '*.zip'
find . | sed 's/$/\.zip/g' | xargs -n 1 rm
It works by searching and expanding all zip files presently in the directory. Later, after it finishes there are potentially new unzipped new files mixed in there too that are not to be deleted yet.
So I delete by finding successfully unzipped *.csv files, and using sed to regenerate the original filenames for deletion which is then fed to rm via the xargs command.

Resources