I'm a newbie to Shell scripting and am trying to make a simple script that can unpack a variety of .tgz , .zip, .tar or .tar.gz archives to the a current directory
i want the script to create a folder equivalent to the base name of the archive and then move the archive to a subdirectory named archive_store
so far i have done the following:
__________________________________
#!/bin/sh
for I in *.tar.gz;
do
A=`basename $I .tar.gz`
mkdir $A
cd $A
gunzip -c ../$I | tar xf -
cd..
done
_____________________________________
Need some help to expand this script to handle the other formats....
Thank you in advance and any help would be greatly appreciated:b:.
Sounds like a case statement. For each file type, assign the commands to use to a set of variables, and then in the main program, simply do what those variables say. Start by refactoring the script you already have, then add more cases. You could start with an easy one like .tgz
untgz () {
gunzip -c <"$1" | tar xf -
}
for l in "$@"; do # invoke this on a bunch of named files
case $l in *.tar.gz) ext=".tar.gz"; command=untgz;; esac
:
A=`basename "$1" "$ext"`
:
$command "$1"
cd ..
done
was able to expand the script using the example as follows... although am unable to make it run... have changed rights of file "chmod 755 filename" and typed "./filename" but there is no result
The : are where you are supposed to use your imagination and/or the code you already wrote. (Sorry for not making that clear.) As it is now, the script simply does basically nothing. Also note the comment which says you invoke it on the files you want to unpack.
No need to have two identical functions, you can use the same function for tar.gz and tgz; and there is no need to write a function for unzip, since you can just say command=unzip and have it use the unzip command you already have on your computer (oh, and take care not to create a recursive function which invokes itself!)
I seem to have mixed up $1 (dollar one) and $l (dollar ell). Inside the function you want the $1 (one) but in the for loop, the file you are currently processing is $l (ell).
okay thanks again era will give it another go... kind of going in circles because there is so much that i dont know.... will try recode in simpler form
Okay so i have got it down to this.... now i am completely lost...
i know that i have to add a few more lines of code on how the files will be handled once uncompressed. ie : mkdir, name=basename. Just unsure of where to start
sorry if im being really draining but i dont know how to structure the last part.....
#!/bin/sh
for file in "$@"
do
case $file in
\*.zip|*.ZIP\)
unzip "$file"
;;
*.tar\)
tar xvpf "$file"
;;
\*.tgz|\*tar.gz|*.tar.Z\)
gunzip -c "$file" | tar xvpf \-
;;
esac
The idea was to put the specific parts in the case statement and then have a general-purpose piece of code just like you had already at the end, except it uses whatever was defined in the case statement above. But okay, here you are.
untgz () {
gunzip -c <"$1" | tar xf -
}
for l in "$@"; do # invoke this on a bunch of named files
case $l in
*.tar.gz) ext=".tar.gz"; command=untgz;;
*.tgz) ext=".tgz"; command=untgz;;
*.tar.Z) ext=".tar.Z"; command=untgz;;
*.zip) ext=".zip"; command=unzip;;
*.ZIP) ext=".ZIP"; command=unzip;;
*) echo "$0: cannot handle $l, skipping" >&2
continue ;;
esac
A=`basename "$l" "$ext"`
mkdir "$A"
cd "$A"
$command "$1"
cd ..
done
The function is required for tar.gz because we want a command which takes exactly one parameter as its last argument, so we have to rearrange things a bit and create a function which does that. For most formats you will simply need to add a command= which already works as specified (archive name is sole argument to command), so you don't need a separate function for it (witness unzip).
The extension handling is kind of ugly; with associative arrays that would be easy to put into a table, but the shell doesn't have that facility. You could still think about ways to make it a bit less atrocious. Maybe a while loop which reads extensions and commands?
# ... code as above, this replaces just the case statement
ext=
while read x cmd; do
case $l in "$x") ext=$x; command=$cmd; break;;
done <<____HERE
.zip unzip
.ZIP unzip
.tar.gz untgz
.tar.Z untgz
.tgz untgz
____HERE
case $ext in '') echo "$0: dunno how to handle $l -- skipping" >&2 ; continue;; esac
# ... continue as before with A=basename etc
Next you will tell us this was a homework assignment and your lecturer didn't understand how "your" code works, and gave you an F. Oh well.
Actually, your code looks good as well, you just need to put the mkdir etc before the case and the cd .. after the case, but then you will need to figure out a new way to extract just the base name of the archive. It's generally a good idea to put all related information in one place, thus I wanted the case statement to contain all the stuff which is specific to each file type.
okay please tell me if i am being annoying.... but i think i have lost track of where to go next.... sorry if im not following your hints but this is a massive learning curve for me. I am truely grateful for your help..
correct me if im wrong but, in the bellow code we have a case statement to handle all the different extension types... then a function "untgz" to handle one parameter at a time... in the main program we have an attempt to handle the basename of the file currently bieng read.
im sorry but could you possibly tell me where to go next. I dont want you to tell me the solution just help me understand what part of my code i need to rewrite, comands to research etc....
If i sound lost it mainly because ive only been using unix and doing shell scripting for three weeks.
thankyou once again
#!/bin/sh
untgz () {
gunzip -c <"$1" | tar xf -
}
for l in "$@";
case $l in
*.tar.gz) ext=".tar.gz"; command=untgz;;
*.tgz) ext=".tgz"; command=untgz;;
*.tar.Z) ext=".tar.Z"; command=untgz;;
*.zip) ext=".zip"; command=unzip;;
*.ZIP) ext=".ZIP"; command=unzip;;
*) echo "$0: cannot handle $l, skipping" >&2
continue ;;
esac
A=`basename "$l" "$ext"` #is this where i should have my while loop?
mkdir "$A"
cd "$A"
$command "$1"
cd ..
done
well when i run it i have various file in the same folder to test i.e - a.tgz , b.tar.gz, c.zip - nothing happens. I have even typed "echo $shell" to see where shell files are located and changed the start of the script to match.
To loop over all files in the current directory, do
for I in *; do ...
You will want to tweak down the diagnostics so it doesn't complain about each and every file it doesn't know how to handle.
You still have $1 in a lot of places where you should now have $I (dollar capital I). Basically anywhere outside the function, you want $I (ih) not $1 (one).
The temporary move of the packed file into the directory where you extract it seems superfluous; just $command ../"$I" instead. If you change that, you will need to make some changes to the code where it moves the file to the store_folder, too.
No, the ... was just to signal that you'd continue as before from that point on.
Just take out the three dots after "do" and fix the one remaining occurrence of $1 (in the case -- you should have case $I in --) and you should be fine. Oh, and you should either not move the file before unzipping it, and use $command "../$I" (there are no spaces between ../ and $I -- it means unzip the file $I in the parent directory), or move the file to the current directory, and omit the ../
You might want to put in some error checking, too: if the directory you want to create already exists, should it just go there anyway, or perhaps add a suffix to the directory name and try again, for example?
Similarly, if you run it on multiple files, store_folder will already exist at least after the first iteration, but it might also exist after a previous run. If nothing else, you probably want to avoid the warnings from attempting to create a directory which already exists. For that particular case, it's probably sufficient to simply check if it exists already, and only if not, try to create it.