Extracting specific file types from all tar files from specific folder - linux

I need shell script which accept two arguments.
First one is path to the specific folder and second one is int value (1 or 2).
If second argument is 1 then I have to go through all tar files in mentioned folder and extract just executable files into specific folder inside path from first argument. in this case name of that folder is "unpacked".
If second argument is 2 then I have to extract all *.txt files from all tar files from folder given by first argument.
I am trying something like this but don't know how to catch every tar file and extract one of these two file types.
#!/bin/bash
cd $1
if [$2 –eq 1 ]
then
for f in *.tar; do
tar –xv –f "$f" –-wildcards EXECUTABLE FILES -C ./unpacked
done
fi
if [$2 –eq 2 ]
then
for f in *.tar; do
tar –xv –f "$f" –-wildcards "*.txt" -C ./unpacked
done
fi

The [MEMBER...] argument must come last.
#!/bin/bash
cd $1
if [$2 –eq 1 ]
then
for f in *.tar; do
tar –xv –f "$f" –-wildcards -C ./unpacked EXECUTABLE FILES
done
fi
if [$2 –eq 2 ]
then
for f in *.tar; do
tar –xv –f "$f" –-wildcards -C ./unpacked "*.txt"
done
fi

To Extract specific files form a tar file execute in yor terminal:
$ tar -zxvf TARNAME.tar.gz PATH/FILNAME

Related

How to extract, rename and view some log files from user inputed tar filename?

The problem is like this :
I need to extract the logs from a tar archive using user input/argument for the file name (cubelog_457890.tar)
In the archive there is just one folder named tftpboot that I need to rename to the original user input.
After that I need to open and view the log files.
#!/bin/bash
fname=$1
if [ -f $fname ]; then
tar -xvzf $fname
fi
mv tftpboot $fname
If I try to use the script with the argument cubelog_457890.tar I have the problem that the MV line will not work.
Starting the script again and using cubelog_457890 will do the job.
How can I make the MV command take cubelog_457890 from user input without the tar extension?
./extract.sh cubelog_457890.tar - will extract but not rename
./extract.sh cubelog_457890 - will rename the folder
try this:
#!/bin/bash
fname=$1
if [[ -f "${fname}.tar" ]]; then
tar -xvf "${fname}.tar"
fi
mv tftpboot $fname
then ./extract.sh cubelog_457890

How do I recursively unzip nested ZIP files?

Given there is a secret file deep inside a nested ZIP file, i.e. a zip file inside a zip file inside a zip file, etc...
The zip files are named 1.zip, 2.zip, 3.zip, etc...
We don't know how deep the zip files are nested, but it may be thousands.
What would be the easiest way to loop through all of them up until the last one to read the secret file?
My initial approach would have been to call unzip recursively, but my Bash skills are limited. What are your ideas to solve this?
Thanks Cyrus! The master wizard Shawn J. Goff had the perfect script for this:
while [ "`find . -type f -name '*.zip' | wc -l`" -gt 0 ]; do find -type f -name "*.zip" -exec unzip -- '{}' \; -exec rm -- '{}' \;; done
Here's my 2 cents.
#!/bin/bash
function extract(){
unzip $1 -d ${1/.zip/} && eval $2 && cd ${1/.zip/}
for zip in `find . -maxdepth 1 -iname *.zip`; do
extract $zip 'rm $1'
done
}
extract '1.zip'
Probably not the cleanest way, but that should do the trick:
#!/bin/sh
IDX=1 # ID of your first zip file
while [ 42 ]
do
unzip $IDX.zip # Extract
if [[ $? != 0 ]]
then
break # Quit if unzip failed (no more files)
fi
if [ $IDX -ne 1 ]
then
rm $IDX.zip # Remove zip to leave your directory clean
fi
(( IDX ++ )) # Next file
done
Checkout this java based utility nzip for nested zips.
Extracting and compressing nested zips can be done easily using following commands:
java -jar nzip.jar -c list -s readme.zip
java -jar nzip.jar -c extract -s "C:\project\readme.zip" -t readme
java -jar nzip.jar -c compress -s readme -t "C:\project\readme.zip"
PS. I am the author and will be happy to fix any bugs quickly.
Here is a solution for windows assuming 7zip is installed in the default location.
#echo off
Setlocal EnableDelayedExpansion
Set source=%1
Set SELF=%~dpnx0
For %%Z in (!source!) do (
set FILENAME=%%~nxZ
)
set FILENAME=%FILENAME:"=%
"%PROGRAMFILES%\7-zip\7z.exe" x -o* -y "%FILENAME%"
REM DEL "%FILENAME%"
rem " This is just to satisfy stackoverflow code formatting!
For %%Z in (!source!) do (
set FILENAME=%%~nZ
)
for %%a in (zip rar jar z bz2 gz gzip tgz tar lha iso wim cab rpm deb) do (
forfiles /P ^"%FILENAME%^" /S /M *.%%a /C "cmd /c if #isdir==FALSE \"%SELF%\" #path"
)
This has been adapted from here https://social.technet.microsoft.com/Forums/ie/en-US/ccd7172b-85e3-4b4a-ad93-5902e0abd903/batch-file-extracting-all-files-from-nested-archives?forum=ITCG
Notes:
The only way to do variable modification using the ~ modifiers is to use a dummy for..in loop. If there is a better way please edit.
~nx modifies the variable to make it a full path+file name.
~dpnx also does the same thing to %0 i.e. gets the full path and filename of the script.
-o* in the 7zip command line allows 7zip to create folder names without the .zip extension like it does when extracting with a right click in the gui.
~n modifies the variable to make it a filename without an extension. i.e. drops the .zip
Note that the escape character (for quotes) in FORFILES /P is ^ (caret) while for the CMD /C it is \. This ensures that it handles path and filenames with spaces also recursively without any problem.
You can remove the REM from the DEL statement if you want the zip file to be deleted after unzipping.

Execute multiple commands on target files from find command

Let's say I have a bunch of *.tar.gz files located in a hierarchy of folders. What would be a good way to find those files, and then execute multiple commands on it.
I know if I just need to execute one command on the target file, I can use something like this:
$ find . -name "*.tar.gz" -exec tar xvzf {} \;
But what if I need to execute multiple commands on the target file? Must I write a bash script here, or is there any simpler way?
Samples of commands that need to be executed a A.tar.gz file:
$ tar xvzf A.tar.gz # assume it untars to folder logs
$ mv logs logs_A
$ rm A.tar.gz
Here's what works for me (thanks to Etan Reisner suggestions)
#!/bin/bash # the target folder (to search for tar.gz files) is parsed from command line
find $1 -name "*.tar.gz" -print0 | while IFS= read -r -d '' file; do # this does the magic of getting each tar.gz file and assign to shell variable `file`
echo $file # then we can do everything with the `file` variable
tar xvzf $file
# mv untar_folder $file.suffix # untar_folder is the name of folder after untar
rm $file
done
As suggested, the array way is unsafe if file name contained space(s), and also doesn't seem to work properly in this case.
Writing a shell script is probably easiest. Take a look at sh for loops. You could use the output of a find command in an array, and then loop over that array to perform a set of commands on each element.
For example,
arr=( $(find . -name "*.tar.gz" -print0) )
for i in "${arr[#]}"; do
# $i now holds each of the filenames output by find
tar xvzf $i
mv $i $i.suffix
rm $i
# etc., etc.
done

for each dir create a tar file

I have a bunch of directories that need to be restored, but they have to first be packaged into a .tar. Is there a script that would allow me to package all 100+ directories into their own tar so dir becomes dir.tar.
So far attempt:
for i in *; do tar czf $i.tar $i; done
The script that you wrote will not work if you have some spaces in a directory name, because the name will be split, and also it will tar files if they exist on this level.
You can use this command to list directories not recursively:
find . -maxdepth 1 -mindepth 1 -type d
and this one to perform a tar on each one:
find . -maxdepth 1 -mindepth 1 -type d -exec tar cvf {}.tar {} \;
Do you have any directory names with spaces in them at that level? If not, your script will work just fine.
What I usually do is write a script with the command I want to execute echoed out:
$ for i in *
do
echo tar czf $i.tar $i
done
Then you can look at the output and see if it's doing what you want. After you've determined that the program will work, edit the command line and remove the echo command.
If there are spaces in the directory names, then just put the variables inside double quotes:
for i in *
do
tar czf "$i.tar" "$i"
done
Get them all done simply and in parallel with GNU Parallel:
parallel tar -cf {}.tar {} ::: *
If you want to check what it is going to do without actually doing anything, add --dry-run like this:
parallel --dry-run tar -cf {}.tar {} ::: *
Sample Output
tar -cf ab.tar ab
tar -cf cd.tar cd
if number of directories are very large and their names are too long
after execution of statement number one
for i in *
do
echo tar czf $i.tar $i
done
you will get error "string too long"

Shell Script for renaming and relocating the files

I am working on something and need to solve the following. I am giving a analogous version of mine problem.
Say we have a music directory, in which there are 200 directories corresponding to different movies. In each movie directory there are some music files.
Now, say a file music.mp3 is in folder movie.mp3 . I want to make a shell script such that it renames the file to movie_music.mp3 and put it in some folder that I mention to it. Basically, all the files in the subdirectories are to be renamed and to be put in a new directory.
Any workaround for this?
This script receives two arguments: the source folder and the destination folder. It will move every file under any directory under the source directory to the new directory with the new filename:
#!/bin.sh
echo "Moving from $1 to $2"
for dir in "$1"/*; do
if [ -d "$dir" ]; then
for file in "$dir"/*; do
if [ -f "$file" ]; then
echo "${file} -> $2/`basename "$dir"`_`basename "${file}"`"
mv "${file}" "$2"/`basename "$dir"`_`basename "${file}"`
fi
done
fi
done
Here is a sample:
bash move.sh dir dir2
Moving from dir to dir2
dir/d1/f1 -> dir2/d1_f1
dir/d1/f2 -> dir2/d1_f2
dir/d2/f1 -> dir2/d2_f1
dir/d2/f2 -> dir2/d2_f2
Bash:
newdir=path/to/new_directory;
find . -type d |while read d; do
find "$d" -type f -maxdepth 1 |while read f; do
movie="$(basename "$d" |sed 's/\(\..*\)\?//')"
mv "$f" "$newdir/$movie_$(basename $f)";
done;
done
Assuming the following directory tree:
./movie1:
movie1.mp3
./movie2:
movie2.mp3
The following one-liner will create 'mv' commands you can use:
find ./ | grep "movie.*/" | awk '{print "mv "$1" "$1}' | sed 's/\(.*\)\//\1_/'
EDIT:
If your directory structure contains only the relevant directories, you can expand use the following grep instead:
grep "\/.*\/.*"
Notice it looks file anything with at least one directory and one file. If you have multiple inner directories, it won't be good enough.

Resources