How to find all tar files in various sub-folders, then extract them in the same folder they were found? - linux

I have lots of sub-folders, with only some containing a tar file. i.e.:
folder1/
folder2/this-is-a.tar
folder3/
folder4/this-is-another.tar
I can find which dirs have the tar by simply doing ls */*.tar.
What I want to achieve is somehow find all .tar files, then extract them in the same directory they are found, then delete the .tars.
I've tried ls */*.tar | xargs -n1 tar xvf but that extracts the tars in in the directory I'm in, not the directory the tars were found.
Any help would be greatly appreciated.

for i in */*.tar ; do pushd `dirname $i` ; tar xf `basename $i` && rm `basename $i` ; popd ; done
Edit: this is probably a better way:
find . -type f -iname "*.tar" -print0 -execdir tar xf {} \; -delete

for file in */*.tar; do
(cd `dirname $file`; tar xvf `basename $file`)
unlink $file
done

Related

Create a empty tar file and then store its name in a variable

I am writing a shell script in which a tar file with today's date and time will be created.
tar -zvcf "log_grabber$(date '+%y-%m-%d_%H%M').tar.gz" --files-from /dev/null
Now, to add more files to this tar files after running the find command. How can I get the name of the tar file and use it in the output of the find command?
find . -type f -name 'local*' -newermt "$user_date" -exec tar -rvf <variable tar file> {} \;
Any help will be very much useful.
Instead of
tar -zvcf "log_grabber$(date '+%y-%m-%d_%H%M').tar.gz" --files-from /dev/null
Create a variable with the name first and use that:
name="log_grabber$(date '+%y-%m-%d_%H%M').tar.gz"
tar -zvcf "$name" --files-from /dev/null
And then:
find . -type f -name 'local*' -newermt "$user_date" -exec tar -rvf "$name" {} +
Note that I changed \; to + so that tar gets multiple files in one invocation, rather than one tar invocation per file.

Move files and directories older than specific time with the same folder structure

I want to move all files and directories are located on /etc/ that are older than 90 days to /old-etc directory but with the same structure in the source directory.
Thanks
Try doing this :
find /etc -mtime +90 -type f -exec bash -c 'install -D "$1" "/old-etc/$1" && rm -f "$1"' -- {} \;

Unzip files in Linux using bash cause errors when path contains spaces

File path like this:
path/path/path/File name 2.3.pdf.zip
What am I doing wrong:
# unzip files back to normal
# and remove zip files
for f in `find "$1" -type f -iname "*.zip"`; do
dir=`dirname "$f"`
unzip -o "$f" -d "$dir"
rm -f "$f"
done
Error message:
unzip: cannot find or open file, file.zip, or file.ZIP
Using UnZip 5.52
Red Hat Enterprise Linux Server release 5.10 (Tikanga)
I think your loop is splitting up the output of find based on the spaces. You may want to do something to read one line at a time, like this
find "$1" -type f -iname "*.zip" | while read f
do
dir=`dirname "$f"`
unzip -o "$f" -d "$dir"
rm -f "$f"
done
Or, alternatively, you could set IFS:
IFS='\n'
for f in `find "$1" -type f -iname "*.zip"`; do
dir=`dirname "$f"`
unzip -o "$f" -d "$dir"
rm -f "$f"
done
Perhaps your problem is here
dir=`dirname $f`
Try instead
dir=`dirname "$f"`
Also, you have some unnecessary semicolons at the end of a few of your lines.

How to untar all .tar.gz with shell-script?

I tried this:
DIR=/path/tar/*.gz
if [ "$(ls -A $DIR 2> /dev/null)" == "" ]; then
echo "not gz"
else
tar -zxvf /path/tar/*.gz -C /path/tar
fi
If the folder has one tar, it works. If the folder has many tar, I get an error.
How can I do this?
I have an idea to run a loop to untar, but I don't know how to solve this problem
for f in *.tar.gz
do
tar zxvf "$f" -C /path/tar
done
I find the find exec syntax very useful:
find . -name '*.tar.gz' -exec tar -xzvf {} \;
{} gets replaced with each file found and the line is executed.
for a in /path/tar/*.gz
do
tar -xzvf "$a" -C /path/tar
done
Notes
This presumes that files ending in .gz are gzipped tar files. Usually .tgz or .tar.gz is used to signify this, however tar will fail if something is not right.
You may find it easier to cd /path/tar first, then you can drop the -C /path/tar from the untar command, and the /path/tar/ in the loop.
The accepted answer worked for me with a slight modification
for f in *.tar.gz
do
tar zxvf "$f" -C \name_of_destination_folder_inside_current_path
done
I had to change the forward slash to a backslash and then it worked for me.

unzip specific extension only

I have a a directory with zip archives containing .jpg, .png, .gif images. I want to unzip each archive taking the images only and putting them in a folder with the name of the archive.
So:
files/archive1.zip
files/archive2.zip
files/archive3.zip
files/archive4.zip
Open archive1.zip - take sunflower.jpg, rose_sun.gif. Make a folder files/archive1/ and add the images to that folder, so files/archive1/folder1.jpg, files/archive1/rose_sun.gif. Do this to each archive.
I really don't know how this can be done, all suggestions are welcome. I have over 600 archives and an automatic solution would be a lifesaver, preferably a linux solution.
In Short
You can do this with a one-liner find + unzip.
find . -name "*.zip" -type f -exec unzip -jd "images/{}" "{}" "*.jpg" "*.png" "*.gif" \;
In Detail
unzip allows you to specify the files you want:
unzip archive.zip "*.jpg" "*.png" "*.gif"
And -d a target directory:
unzip -d images/ archive.zip "*.jpg" "*.png" "*.gif"
Combine that with a find, and you can extract all the images in all zips:
find . -name "*.zip" -type f -exec unzip -d images/ {} "*.jpg" "*.png" "*.gif" \;
Using unzip -j to junk the extraction of the zip's internal directory structure, we can do it all in one command. This gives you the flat image list separated by zip name that you desire as a one-liner.
find . -name "*.zip" -type f -exec unzip -jd "images/{}" "{}" "*.jpg" "*.png" "*.gif" \;
A limitation is that unzip -d won't create more than one new level of directories, so just mkdir images first. Enjoy.
7zip can do this, and has a Linux version.
mkdir files/archive1
7z e -ofiles/archive1/ files/archive1.zip *.jpg *.png *.gif
(Just tested it, it works.)
Something along the lines of:
#!/bin/bash
cd ~/basedir/files
for file in *.zip ; do
newfile=$(echo "${file}" | sed -e 's/^files.//' -e 's/.zip$//')
echo ":${newfile}:"
mkdir tmp
rm -rf "${newfile}"
mkdir "${newfile}"
cp "${newfile}.zip" tmp
cd tmp
unzip "${newfile}.zip"
find . -name '*.jpg' -exec cp {} "../${newfile}" ';'
find . -name '*.gif' -exec cp {} "../${newfile}" ';'
cd ..
rm -rf tmp
done
This is tested and will handle spaces in filenames (both the zip files and the extracted files). You may have collisions if the zip file has the same file name in different directories (you can't avoid this if you're going to flatten the directory structure).
You can write a program using a zip library. If you do Mono, you can use DotNetZip.
The code would look like this:
foreach (var archive in listOfZips)
{
using (var zip = ZipFile.Read(archive)
{
foreach (ZipEntry e in zip)
{
if (IsImageFile(e.FileName))
{
e.FileName = System.IO.Path.Combine(archive.Replace(".zip",""),
System.IO.Path.GetFileName(e.FileName));
e.Extract("files");
}
}
}
}
Perl's Archive-Zip is a good library for zipping/unzipping.
Here's my take on the first answer...
#!/bin/bash
cd files
for zip_name in *.zip ; do
dir_name=$(echo "${zip_name}" | sed -e 's/^files.//' -e 's/.zip$//')
mkdir ${dir_name}
7z e -o${dir_name}/ ${zip_name} *.jpg *.png *.gif
done
or, if you'd just like to use the regular unzip command...
unzip -d ${dir_name}/ ${zip_name} *.jpg *.png *.gif
I haven't tested this, but it should work... or something along these lines. Definitely more efficient than the first solution. :)
Hope this helps!

Resources