ult/Section_5.rst
changeset 125 343a405d0aca
parent 124 fe7f10950014
child 126 b9c6563869ef
child 132 24cec0337e81
equal deleted inserted replaced
124:fe7f10950014 125:343a405d0aca
     1 tar:
       
     2 ====
       
     3 
       
     4 Introduction:
       
     5 -------------
       
     6 
       
     7 In world of Linux based distribution, *tarballs* is the term which pops up very often. It is part of the GNU project and comes as part of every distribution of GNU/Linux. Tarball is like defacto standard for releasing source code for free software. Some of common use of *tar* archives is to: *Store, backup, and transport*.
       
     8 
       
     9 GNU tar creates and manipulates archives which are actually collections of many other files; the program provides users with an organized and systematic method for controlling a large amount of data. It is basically form of creating archive by concatenating one or more files. 
       
    10 
       
    11 Getting Started:
       
    12 ---------------------------
       
    13 
       
    14 As mentioned previously and if not, *The best way to get started with any command line tool of Linux is to use "man".* ::
       
    15 
       
    16    $ man tar
       
    17 
       
    18 or try these commands(the output may vary with different installations): ::
       
    19 
       
    20    $ tar --version
       
    21    tar (GNU tar) 1.20
       
    22    Copyright (C) 2008 Free Software Foundation, Inc.
       
    23    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
       
    24    This is free software: you are free to change and redistribute it.
       
    25    There is NO WARRANTY, to the extent permitted by law.
       
    26 
       
    27    Written by John Gilmore and Jay Fenlason.
       
    28 
       
    29    $ tar --help
       
    30    Usage: tar [OPTION...] [FILE]...
       
    31    GNU `tar' saves many files together into a single tape or disk archive, and can
       
    32    restore individual files from the archive.
       
    33    Examples:
       
    34    tar -cf archive.tar foo bar  # Create archive.tar from files foo and bar.
       
    35    tar -tvf archive.tar         # List all files in archive.tar verbosely.
       
    36    tar -xf archive.tar          # Extract all files from archive.tar.  
       
    37    ____________
       
    38 
       
    39 Creating a tar archive: 
       
    40 ~~~~~~~~~~~~~~~~~~~~~~~
       
    41 
       
    42 We will do some off-the road activity for this exercise. We will use an interesting command *fortune* for creating our practice files and then performing archives of those files and directories. Content of the files would vary for users, as fortune works like that. ::
       
    43 
       
    44    $ mkdir fortune-files 
       
    45    $ cd fortune-files/
       
    46    $ fortune > first.txt
       
    47    $ cat first.txt 
       
    48    Expect the worst, it's the least you can do.
       
    49    $ fortune > second.txt
       
    50    $ fortune > third.txt
       
    51    $ ls
       
    52    first.txt  second.txt  third.txt
       
    53 
       
    54 By now we have three txt files, with some random fortune content. To create a tar archive of these files we can use any of following commands according to ones convenience: ::
       
    55 
       
    56    $ tar --create --verbose --file=allfiles.tar first.txt second.txt third.txt
       
    57    first.txt
       
    58    second.txt
       
    59    third.txt
       
    60    $ ls
       
    61    allfiles.tar  first.txt  second.txt  third.txt
       
    62 
       
    63 allfiles.tar is our required tar archive of all the rest of files(or archive of files mentioned in command line). Other form of the previous command are: ::
       
    64 
       
    65    $ tar -c -v -f allfiles.tar first.txt second.txt third.txt
       
    66 
       
    67 or ::
       
    68 
       
    69    $ tar -cvf allfiles.tar first.txt second.txt third.txt
       
    70    
       
    71 The general format for creating a tar archive is: ::
       
    72    
       
    73    tar [OPTION...] [FILE]... 
       
    74 
       
    75 For our command are using these options:
       
    76 
       
    77    * -c to Create the archive.
       
    78    * -v for Verbose mode, to get the names of the files as they are archived.
       
    79    * -f mentioning the file name of the resulting tar archive.
       
    80 
       
    81 To create archive of folder itself try this: ::
       
    82    
       
    83    $ tar -cvf fortune.tar fortune/
       
    84 
       
    85 To add files to existing tar archive, option *`r`* is used: ::
       
    86 
       
    87    $ fortune > fourth.txt
       
    88    $ tar -r fourth.txt -vf allfiles.tar
       
    89    fourth.txt
       
    90 
       
    91 There are other options too available for explicitly mentioning the position of archive, use *tar --help* for getting all the details.
       
    92 
       
    93 Similarly to remove file from archive use *--delete* option: ::
       
    94 
       
    95    $ tar --delete second.txt -f allfiles.tar
       
    96    $ tar -tf allfiles.tar
       
    97    first.txt
       
    98    third.txt
       
    99    fourth.txt
       
   100 
       
   101 Listing the files of archive:
       
   102 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
   103 
       
   104 Once files are archived, tar command have the *`t`* option, for Listing all files in the tar file: ::
       
   105 
       
   106    $ tar tf allfiles.tar
       
   107    first.txt
       
   108    second.txt
       
   109    third.txt
       
   110 
       
   111 **//this is not working for me in some cases :(**
       
   112 
       
   113 To locate a particular file among the archive mention its name after *t* option. ::
       
   114 
       
   115    $ tar t second.txt allfiles.tar
       
   116    second.txt
       
   117 
       
   118 one can also use elementary regex for locating the file, so in previous case even second.* will also return the same result.
       
   119 
       
   120 Extracting files from archive:
       
   121 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
   122 
       
   123 To extract the content from a archive, use *`x`* option: ::
       
   124 
       
   125    $ mkdir extract
       
   126    $ cp allfiles.tar extract/
       
   127    $ cd extract
       
   128    $ tar -xvf allfiles.tar 
       
   129    first.txt
       
   130    second.txt
       
   131    third.txt
       
   132 
       
   133 To extract any particular file from archive, mention the name of file after *x* option: ::
       
   134 
       
   135    $ tar -x second.txt -vf allfiles.tar 
       
   136    second.txt
       
   137    
       
   138     
       
   139 
       
   140 GZip:
       
   141 =====
       
   142 
       
   143 Tar creates archives but it does not compress data by itself unless specified explicitly. Hence all the archive we create using tar command, is simply of the size of total size of all individual files. With Linux there is a compression tool known as *gzip* which is used to reduce the size of files mentioned. Whenever possible, each file is replaced by one with the extension `.gz', so unlike `tar` this command would *replace the existing file*.
       
   144 
       
   145 Get going:
       
   146 ----------
       
   147 
       
   148 As usual first commands to check out with gzip are *man* and *help*, ::
       
   149 
       
   150     $ man gzip
       
   151     $ gzip --help
       
   152 
       
   153 Creating a zip of a bunch of files is fairly trivial, it can be done simply via: ::
       
   154 
       
   155     $ gzip [OPTION]... [FILE]...
       
   156     
       
   157 Creating zip files:
       
   158 ~~~~~~~~~~~~~~~~~~~
       
   159 
       
   160 Continuing from previous set of files and setup, we will like to zip them and hence the command would be: ::
       
   161 
       
   162     $ gzip first.txt fourth.txt second.txt third.txt
       
   163     $ ls
       
   164     allfiles.tar  first.txt.gz  fourth.txt.gz  second.txt.gz  third.txt.gz  zipped.tar.gz
       
   165 
       
   166 Hence, as mentioned above, all original files are replaced by .gz extension. The above task can also be restated and made easy with help of some common regex expression: ::
       
   167 
       
   168     $ gzip *.txt
       
   169 
       
   170 Similar to *tar* command, one can also use *`-v`* option here to see the output in *verbose* form. For the previous example, if we enable this option the result would be something like this: ::
       
   171 
       
   172     $ gzip -v *.txt
       
   173     first.txt:	  4.4% -- replaced with first.txt.gz
       
   174     fourth.txt:	 -7.1% -- replaced with fourth.txt.gz
       
   175     second.txt:	 -4.8% -- replaced with second.txt.gz
       
   176     third.txt:	  3.8% -- replaced with third.txt.gz    
       
   177 
       
   178 
       
   179 
       
   180     $ gzip -c *.txt > all.gz 
       
   181 
       
   182 Now in this case, all files would be zipped, concatenated and then the output would be written to a file all.gz leaving back all the original files. In the command above *`-c`* option states to print the output to standard output(stdout) and following *`>`* would redirect the output to file all.gz. So when we decompress this file, we will get a single file named 'all' with all the content of each files concatenated one after the another. 
       
   183 
       
   184 For creating a zip archive of a complete directory, one has to use *`-r`* options which means recursive, it makes gzip to traverse through all directory tree/structure. By default it will create zip files of each file inside the directory, that is even with the -r flag, gzip still compresses one file at a time : ::
       
   185 
       
   186     $ gzip -r fortune-files/
       
   187     $ gzip -rv .
       
   188     ./first.txt:	  4.4% -- replaced with ./first.txt.gz
       
   189     ./second.txt:	 -4.8% -- replaced with ./second.txt.gz
       
   190     ./third.txt:	  3.8% -- replaced with ./third.txt.gz
       
   191     ./allfiles.tar:	 96.6% -- replaced with ./allfiles.tar.gz
       
   192     ./fourth.txt:	 -7.1% -- replaced with ./fourth.txt.gz
       
   193 
       
   194 Hence one always sees files like something.tar.gz, to create a zip of whole directory in a single file, first archive everything inside a folder and then use gzip on that. For zipping the files using tar itself, one has to use the option *`g`*. ::
       
   195 
       
   196 
       
   197 
       
   198     $ tar -cvzf zipped.tar.gz *.txt 
       
   199     first.txt
       
   200     fourth.txt
       
   201     second.txt
       
   202     third.txt
       
   203 
       
   204 *Thats why gzip is designed as a complement to tar, not as a replacement.*
       
   205 
       
   206 gzip command comes with a option *`-l`* to view the compressed file contents: ::
       
   207 
       
   208     $ gzip -l zipped.tar.gz
       
   209              compressed        uncompressed  ratio uncompressed_name
       
   210                 332               10240      97.0% zipped.tar
       
   211 
       
   212 
       
   213 
       
   214 To decompress a already compressed file there are two options, either use *`gunzip`* command or use *`-d`* option with gzip command: ::
       
   215 
       
   216     $ gzip -dv *.gz 
       
   217     all.gz:	-440.4% -- replaced with all
       
   218     first.txt.gz:	  4.4% -- replaced with first.txt
       
   219     fourth.txt.gz:	 -7.1% -- replaced with fourth.txt
       
   220     second.txt.gz:	 -4.8% -- replaced with second.txt
       
   221     third.txt.gz:	  3.8% -- replaced with third.txt
       
   222     zipped.tar.gz:	 97.0% -- replaced with zipped.tar
       
   223 
       
   224 or: ::
       
   225     
       
   226     $ gunzip -v *.gz
       
   227 
       
   228 Both of those commands will give the same result. So here one can notice the content of file "all" which we created earlier, it will have content of all the rest of four files concatenated one after another, but "zipped.tar.gz" is zip of tar of all files, will effectively have zip of archives of all files separately, and hence the usage and importance of *tar*.
       
   229 
       
   230 Further Reading for this section:
       
   231 ---------------------------------
       
   232 
       
   233 	* http://linuxreviews.org/beginner/
       
   234 	* http://lowfatlinux.com/linux-gzip-gunzip.html
       
   235 	* http://www.gnu.org/software/gzip/manual/gzip.html
       
   236 	* http://en.wikipedia.org/wiki/ZIP_(file_format)
       
   237 
       
   238 
       
   239 File Comparisons:
       
   240 =================
       
   241 
       
   242 Linux based distributions also have some utilities for checking the content of files, comparing them very quickly to other files. These operations can be looking for differences/similarities. Some of the commands which prove handy are: 
       
   243 
       
   244 cmp:
       
   245 ----
       
   246 
       
   247 If one wants to compare two files whether they are same or not, one can use this handy tool. Let us consider some situation, we run find/locate command to locate some file, and it turns out that we have a file with same name in different location, and in case we want to run a quick check on there content, cmp is the right tool. Usage  ::
       
   248 
       
   249    $ cmp Desktop/programs/quick.c c-folder/quick.c
       
   250    Desktop/programs/quick.c c-folder/quick.c differ: byte 339, line 24
       
   251 
       
   252 That is, if files differ, the byte and line number at which the first difference occurred is reported. 
       
   253  
       
   254 diff:
       
   255 -----
       
   256 
       
   257 Now there are situations when one wants to exactly know the differences among two files, for them, GNU diff can show whether files are different without detailing the differences. For simple and basic usage of this programs, consider following example: ::
       
   258 
       
   259     $ echo -e "quick\nbrown\nfox\njumped\nover\nthe\nlazy\ndog" > allcorrect.txt
       
   260     $ echo -e "quick\nbrown\nfox\njmuped\nover\nteh\nlzay\ndog" > incorrect.txt
       
   261     $ diff problem.txt allc.txt 
       
   262     4c4
       
   263     < jmuped
       
   264     ---
       
   265     > jumped
       
   266     6,7c6,7
       
   267     < teh
       
   268     < lzay
       
   269     ---
       
   270     > the
       
   271     > lazy
       
   272 
       
   273 Looking at results above mentioned it is very trivial to deduce that, diff if used on two separate text files will result in line by line results for all the lines which are different. So most common use case scenario can be, got some files in various location of system with same name and size, just run diff through them and remove all the redundant files. Other similar command which one can find more effective for this can be *sdiff*, for the same files using sdiff will result in: ::
       
   274 
       
   275     $ sdiff incorrect.txt allcorrect.txt 
       
   276     quick								quick
       
   277     brown								brown
       
   278     fox									fox
       
   279     jmuped							      |	jumped
       
   280     over								over
       
   281     teh								      |	the
       
   282     lzay							      |	lazy
       
   283     dog								      	dog   
       
   284 
       
   285 
       
   286 comm:
       
   287 -----
       
   288 
       
   289 This is one more command which proves handy at times, the short and sweet man page states "compare two sorted files line by line". Or this it compares sorted files and selects or rejects lines common to two files. For ex: ::
       
   290 
       
   291    $ sort allcorrect.txt>sortedcharac.txt; sort incorrect.txt>sortedprob.txt
       
   292    $ comm sortedcharac.txt sortedprob.txt 
       
   293 		brown
       
   294 		dog
       
   295 		fox
       
   296 	jmuped
       
   297    jumped
       
   298    lazy
       
   299 	lzay
       
   300 		over
       
   301 		quick
       
   302 	teh
       
   303    the
       
   304 
       
   305 Environment Variables:
       
   306 ======================
       
   307 
       
   308 These variables like HOME, OSTYPE,Variables are a way of passing information from the shell to programs when you run them. Programs look "in the environment" for particular variables and if they are found will use the values stored. Standard UNIX variables are split into two categories, environment variables and shell variables. In broad terms, shell variables apply only to the current instance of the shell and are used to set short-term working conditions; environment variables have a farther reaching significance, and those set at login are valid for the duration of the session.By convention, environment variables have UPPER CASE and shell variables have lower case names.  
       
   309 
       
   310 Some of examples of Environment variables are: ::
       
   311 
       
   312    $ echo $OSTYPE 
       
   313    linux-gnu
       
   314    $ echo $HOME
       
   315    /home/user 
       
   316 
       
   317 To see all the variables and there values use any of following commands: ::
       
   318 
       
   319    $ printenv | less
       
   320    $ env
       
   321 
       
   322 The most commonly used environment variable is "PATH", it defines a list of directories to search through when looking for a command to execute. If you decide to put your own programs in a bin directory under your home directory, you'll have to modify the path to include that directory, or the system will never find your programs (unless you happen to be in that directory when you enter the command). Here's how to change your PATH variable so it includes your personal bin directory: ::
       
   323 
       
   324    $ set PATH=$PATH:$HOME/bin
       
   325 
       
   326 See the difference in value of PATH variable before and after modifying it. One can also create its own variable to make things easier: ::
       
   327 
       
   328    $ set repo = $HOME/Desktop/random/code
       
   329    $ cd $repo
       
   330 
       
   331 *set* command is used to define a variable for the current shell. Try opening a new shell and use the above mentioned command, it wont work as expected. The other child process wont be able to see these variables unless we *export* them. Repeat the above mentioned activity with *export* command. Now with all new shells, *$repo* will work.
       
   332 
       
   333 
       
   334 
       
   335 
       
   336 
       
   337 Shell Scripting:
       
   338 ================
       
   339 
       
   340 Basics:
       
   341 -------
       
   342 
       
   343 Shell program or shell script,a sequence of commands to a text file and tell the shell to execute the text file instead of entering the commands. The first *"Hello World"* sample for shell scripting is as easy as it sounds: ::
       
   344 
       
   345    $ echo '#!/bin/sh' > my-script.sh
       
   346    $ echo 'clear' >> my-script.sh   
       
   347    $ echo 'echo Hello World' >> my-script.sh
       
   348    $ chmod 755 my-script.sh
       
   349    $ ./my-script.sh
       
   350    Hello World
       
   351 
       
   352 The #! syntax(also known as shebang) is used in scripts to indicate an interpreter for execution under UNIX / Linux operating systems. The chmod is required to make the script executable. This script will just execute two commands, *clear* and *echo* one after another. One can also do the same task using a one liner command *clear; echo 'Hello World';* but as number of lines grows using a script file is helpful. 
       
   353 
       
   354 So lets create a script which gives us all the filenames for given initial alphabet or string in a directory. Let the name of script be *initial.sh*, open it with text editor, and write: ::
       
   355 
       
   356    #!/bin/sh
       
   357    ls > temp
       
   358    grep ^$1 < temp
       
   359    rm temp
       
   360    $ chmod a+x initial.sh
       
   361    $ ./initial.sh s
       
   362 
       
   363 The $1 in the script is pertaining to command line argument. All arguments passed via command line are accessed via *$#* with name of script being first member, that is $0. Now lets write a script for finding a file, and then checking when was it last modified: ::
       
   364 
       
   365    #!/bin/sh
       
   366    name=`find . -name $1 -print`
       
   367    echo $name
       
   368    last_modified=`stat -c %y $name| cut -f 1 -d " "`
       
   369    echo "Last modified: $last_modified"    
       
   370    $ ./search.sh fname
       
   371 
       
   372 Try giving some file you want to search in place of fname. Please note in second line *`* its a back-quote(other key mapped with tilda), it is specifically used to get the output of one command into a variable. In this particular case name is a User defined variables  which stores the value. We access value stored in any variable using *$* symbol before name of variable.
       
   373 
       
   374 
       
   375 
       
   376 Shell Arithmetic:
       
   377 -----------------
       
   378 
       
   379 Shell also provides support for basic arithmetic operations. The syntax is: ::
       
   380 
       
   381    $ expr op1 math-operator op2
       
   382 
       
   383 Some of example which can be tried handily: ::
       
   384    
       
   385    $ expr -3 + 5
       
   386    2
       
   387    $ expr 10 % 3
       
   388    1
       
   389 
       
   390 These spaces in between operator and operands is important, without them shell interpreter will raise the syntax error. ::
       
   391 
       
   392    $ expr 2*3
       
   393    expr: syntax error
       
   394    
       
   395 One can use back-quotes(`) also to get value of expr. ::
       
   396 
       
   397    $ echo `expr 6 + 3`
       
   398    9
       
   399    $ result=`expr 6 + 3`
       
   400    $ echo $result
       
   401    9
       
   402 
       
   403 Shell uses three kinds of quotes. Double quotes("), anything enclosed among them except from variable trailing after $, and characters after \ would be printed as it is. Single quotes('), anything enclosed within them is just same, no formulation/interpretation. Back quotes(`), anything inclosed is considered as command, or is executed. ::
       
   404 
       
   405    $ echo "Today is date"
       
   406    Today is date
       
   407    $ echo "Today is `date`"
       
   408    Today is Wed Sep 16 17:32:22 IST 2009
       
   409    $ echo 'Today is `date`'
       
   410    Today is `date`
       
   411    $ echo "Today is \n `date`"
       
   412    Today is \n Wed Sep 16 17:40:13 IST 2009
       
   413    $ echo -e "Today is \n `date`"
       
   414    Today is 
       
   415     Wed Sep 16 17:41:13 IST 2009 
       
   416 
       
   417 if else construct:
       
   418 ------------------
       
   419 
       
   420 One can have simple *if else if* constructs in shell scripts to check conditions. Lets take simple example of writing a script which returns back whether the argument passed is positive or not: ::
       
   421 
       
   422    #!/bin/sh
       
   423    if test $1 -gt 0
       
   424    then
       
   425      echo "number is positive"
       
   426    else
       
   427      echo "number is negative"
       
   428    fi
       
   429    $ ./sign.sh -11
       
   430    number is negative
       
   431 
       
   432 This script will compare the first value passed as argument with 0 *if test var -gt val*, var being $1 and val being 0, gt meaning greater then. Now this program has some flaw, it will give same result for following input: (-11) and (-1, 5), as we are checking just $1 which is first argument and hence the result. For handling such situation we can include *if-else* clause which will warn user of correct usage of script. ::
       
   433 
       
   434    #this is the case when no argument is passed  
       
   435    if [ $# -eq 0 ]
       
   436    then
       
   437      echo "$0 : You must give/supply one integers"
       
   438      exit 1
       
   439    else 
       
   440      if [ $# -gt 1 ]
       
   441      then
       
   442        echo "$0 : You must give one integer"
       
   443        exit 1
       
   444      fi
       
   445    fi
       
   446 
       
   447 One important thing to note in shell script is spacing, with many comparison and evaluation operation a wrongly placed space will spoil all the fun. So in previous example the expression *[ $# -eq 0 ]* will work properly, but if we remove those leading or trailing spaces like *[ $# -eq 0]*, it wont work as expected, or rather throw a warning. Both *test* and *[]* do the same task of testing a expression and returning true or false.
       
   448 
       
   449 Lets create something interesting using these if-else clause. Now we will create a script which will greet the user when he opens the shell. We will create the script, change the permission to make it executable and append the *.bashrc* file with *./greet.sh* line and we are done. The script is: ::
       
   450 
       
   451    #!/bin/sh
       
   452    #Script to greet the user according to time of day
       
   453    temph=`date | cut -c12-13`
       
   454    dat=`date +"%A %d in %B of %Y (%r)"`
       
   455    if [ $temph -lt 12 ]
       
   456    then
       
   457      mess="Good Morning $LOGNAME, Have a nice day!"
       
   458    fi
       
   459 
       
   460    if [ $temph -gt 12 -a $temph -le 16 ]
       
   461    then
       
   462      mess="Good Afternoon $LOGNAME"
       
   463    fi
       
   464 
       
   465    if [ $temph -gt 16 -a $temph -le 18 ]
       
   466    then
       
   467      mess="Good Evening $LOGNAME"
       
   468    fi
       
   469    echo -e "$mess\nThis is $dat"
       
   470 
       
   471 For me when I open the shell the output is something like: ::
       
   472 
       
   473    Good Morning user, Have a nice day!
       
   474    This is Wednesday 16 in September of 2009 (11:54:47 AM IST) 
       
   475 
       
   476 Loops
       
   477 -----
       
   478 
       
   479 Bash has three different commands for looping -- ``for``, ``while`` and ``until``. 
       
   480 
       
   481 ``for`` loop
       
   482 ~~~~~~~~~~~~
       
   483 
       
   484 Suppose we have a set of files, that have names beginning with numbers followed by their names - ``08 - Society.mp3``. We would like to rename these files to remove the numbering. How would we go about doing that? It is clear from the problem statement that we could use a ``for`` loop, to loop through the list of files and rename each of the files.  
       
   485 
       
   486 Let's first look at a simple ``for`` loop, to understand how it works. 
       
   487 ::
       
   488 
       
   489   for animal in rat cat dog man
       
   490   do 
       
   491     echo $animal
       
   492   done
       
   493 
       
   494 We just wrote a list of animals, each animal's name separated by a space and printed each name on a separate line. The variable ``animal`` is a dummy variable and has no significance. You could use something as lame as ``i`` in place of ``animal``.  
       
   495 
       
   496 Now, we use a simple ``for`` loop to list the files that we are interested in. 
       
   497 ::
       
   498 
       
   499   ls *.mp3 > list
       
   500   for i in `cat list`
       
   501   do
       
   502     echo "$i"
       
   503   done
       
   504 
       
   505 If your filenames contain spaces, ``for`` assumes each space separated word to be a single item in the list and prints it in a separate line. We could change the script slightly to overcome this problem. 
       
   506 ::
       
   507 
       
   508   for i in *.mp3
       
   509   do
       
   510     echo "$i"
       
   511   done
       
   512 
       
   513 Now, we have each file printed on a separate line. Depending on the files that we have we could use grep to get the relevant portion of the filenames and rename the files. 
       
   514 ::
       
   515 
       
   516   for i in *.mp3
       
   517   do 
       
   518     j=$(echo "$i"|grep -o "[A-Za-z'&. ]*.mp3")
       
   519     echo "$i -> $j"
       
   520   done
       
   521 
       
   522 Now we just replace the echo command with a ``mv``  command. 
       
   523 ::
       
   524 
       
   525   for i in *.mp3
       
   526   do 
       
   527     j=$(echo "$i"|grep -o "[A-Za-z'&. ]*.mp3")
       
   528     mv "$i" "$j"
       
   529   done
       
   530 
       
   531 
       
   532 
       
   533 ``while``
       
   534 ~~~~~~~~~
       
   535 
       
   536 The ``while`` command allows us to continuously execute a block of commands until the command that is controlling the loop is executing successfully. 
       
   537 
       
   538 Let's start with the lamest example of a while loop.
       
   539 ::
       
   540 
       
   541   while true
       
   542   do
       
   543     echo "True"
       
   544   done
       
   545 
       
   546 This, as you can see, is an infinite loop that prints the ``True``. 
       
   547 
       
   548 Say we wish to write a simple program that takes user input and prints it back, until the input is ``quit``, which quits the program. 
       
   549 ::
       
   550 
       
   551   while [ "$variable" != "quit" ]
       
   552   do
       
   553     read variable
       
   554     echo "Input - $variable"
       
   555   done
       
   556   exit 0
       
   557 
       
   558 ``until``
       
   559 ~~~~~~~~~
       
   560 
       
   561 The ``until`` loop is similar to the ``while`` loop, except that it executes until the conditional command does not execute properly. 
       
   562 
       
   563 The infinite loop changes to the following, when ``until`` is used.
       
   564 ::
       
   565 
       
   566   until false
       
   567   do
       
   568     echo "True"
       
   569   done
       
   570 
       
   571 Now lets try and use these above mentioned options provided by shell to write a utility. Until now, when we try find or locate it looks through directories and files for result. But they wont search through tar archives and zipped files. Lets create a shell script for especially looking through these files
       
   572 ::
       
   573 
       
   574   #!/bin/sh
       
   575 
       
   576   #To check number of arguments being passed.
       
   577   if [ $# -eq 0 ] ; then
       
   578   echo "Correct usage: $0 tar-archive filename \nOr $0 filename"
       
   579   exit 1
       
   580   else
       
   581     if [ $# -eq 1 ] ; then
       
   582       tar_archive=`find $PWD -name "*.tar*"`
       
   583     else
       
   584       tar_archive=`find $PWD -name $1`
       
   585     fi
       
   586   fi
       
   587 
       
   588   #Search of particular file inside archives.
       
   589   for archive in $tar_archive
       
   590   do
       
   591     echo $archive
       
   592     variable=`tar -tf $archive`
       
   593     for word in $variable
       
   594     do
       
   595       if [ $# -eq 1 ] ; then
       
   596         echo "$word" | grep -q ".*$1"
       
   597       else
       
   598 	echo "$word" | grep -q ".*$2"
       
   599       fi
       
   600     if [ $? -eq 0 ] ; then 
       
   601       echo "File present in $archive!" 
       
   602     fi  
       
   603     done
       
   604   done
       
   605 
       
   606 
       
   607 Functions
       
   608 ---------
       
   609 
       
   610 When a group of commands are repeatedly being used within a script, it is convenient to group them as a function. This saves a lot of time and you can avoid retyping the code again and again. Also, it will help you maintain your code easily. Let's see how we can define a simple function, ``hello-world``. Function can be defined by using function name followed by a pair of parentheses. 
       
   611 ::
       
   612 
       
   613   
       
   614   hello-world () {
       
   615     echo "Hello, World.";
       
   616   }
       
   617 
       
   618   $ hello-world
       
   619   Hello, World.
       
   620 
       
   621 Passing parameters to functions is similar to passing them to scripts. 
       
   622 ::
       
   623 
       
   624 
       
   625   #! /bin/bash
       
   626 
       
   627   hello-name()
       
   628   {
       
   629      echo  "hello ". $1
       
   630         
       
   631   }
       
   632 
       
   633   hello-name $1
       
   634 
       
   635 
       
   636   #!usr/bin/bash
       
   637   hello-name
       
   638   { 
       
   639   echo "Hello, $1."; 
       
   640   }
       
   641 
       
   642   hello-name $1
       
   643 
       
   644   save this in a file helloscipt.sh and give it execute permission
       
   645   
       
   646 
       
   647   $ ./helloscipt 9
       
   648   Hello, 9.
       
   649 
       
   650 Any variables that you define within a function, will be added to the global namespace. If you wish to define variables that are restricted to the scope of the function, define a variable using the ``local`` built-in command of bash.
       
   651 
       
   652   
       
   653 We shall now write a function for the word frequency generating script that we had looked at in the previous session. 
       
   654 
       
   655 ::
       
   656 
       
   657   word_frequency() {
       
   658     if [ $# -ne 1 ]
       
   659     then
       
   660       echo "Usage: $0 file_name"
       
   661       exit 1
       
   662     else 
       
   663       if [ -f "$1" ]
       
   664       then
       
   665         grep  "[A-Za-z]*" -o "$1" | tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | less
       
   666       fi
       
   667     fi
       
   668   }
       
   669 
       
   670  word_frequency  $1
       
   671 
       
   672 
       
   673 
       
   674