![]() |
| |||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Here is a useful script to solve a common problem when transferring text files between tradition Mac text editors and Unix editors. The script demonstrates the use of the 'if' statement. Background: Traditionally, a Mac text file uses Return (ASCII 13) as an end of line character. Unix uses Line Feed (ASCII 10) as an end of line character. Edit a Mac-style text file with a Unix editor and you will see the file as one long line interspersed with '^M's. The following script converts Mac end of line characters into Unix style end of line characters. It has two parts, the first checks that the script was given a file to convert, and the second actually does the conversion. % cat mac2unix #!/bin/sh The script uses an 'if' statement to decide whether or not to proceed, base on whether or not a filename was given. if [ "$1" = "" ]is testing if the first parameter -$1- is empty or not. If the condition is true (no arguments where given when the script was run) the script executes the 'then' part between 'then' and 'fi'. This simply echoes a usage line and exits the script. If the condition is false (a filename was given), the 'if' statement is skipped - i.e. everything up to 'fi' is skipped. The script proceeds with the line 'tmp=$(./gen-tmp)'. The line: tmp=$(./gen-tmp)is calling script 'gen-tmp' and setting the variable 'tmp' to equal its output (just as we did for 'date=$(date)' in the 'vars.sh' script above). 'gen-tmp' generates a temporary filename (below). The line: tr \\r \\n < $1 > $tmp ; mv $tmp $1is doing the actual conversion using the Unix command 'tr'. Note the use of $tmp and $1. Part 7 explains the redirection operators '<' and '>', and 'man tr' will explain how 'tr' itself works. The second script looks like this: % cat gen-tmp #!/bin/sh tmp=/tmp/$UID$(date +%H%M%S) echo $tmp The script sets variable tmp to be '/tmp/' followed by the user's UID and the current time, in order to generate a unique filename - or rather pathname. The line 'echo $tmp' causes the output of the script to be the generated filename. For example: % ./gen-tmp /tmp/501130202 The filename is grabbed by the first script and assigned to variable 'tmp' in the line: tmp=$(./gen-tmp)The mac2unix script can be improved by removing the 'exit' statement from within 'if...fi' and using and 'if...else...fi' construct. What we really want to say is this: if no filename given output a usage line else do the conversion fi The 'else' part is executed when the 'if' condition is false, so either the 'if' part or the 'else' part is executed, but never both. Here is the new script: % cat mac2unix2 #!/bin/sh |
Tell Me More...
|
|
Parameters to 'echo' What is the difference between: echo Adrian Mayo and echo "Adrian Mayo" The first passes two parameters/arguments to echo, 'Adrian' and 'Mayo', which are echoed with a single space between them. The second passes a single argument to echo, which is echoed verbatim, with many spaces. Globbing When issuing a command such as: ls -l *'ls' does not get the star. Instead, the shell interprets the star as a wildcard and expands it to be all the files in the current directory. 'ls' sees the first argument '-l', then one argument for each file in the current directory. Try the same with the 'params.sh' script: ./params.sh *Why the Double Quotes in "$1" = ""?Without them, the statement would read: [ $1 = ]which is illegal syntax. Even a condition like: [ $1 = Hello ]requires quotes. If $1 were empty the condition would expand to: [ = Hello ]which again is illegal syntax. UID? $UID is an environment variable that is always available and set to the user's UID (see Part 4.) Try: echo $UIDon the command line (Bourne shell). Indentation Notice that I have indented some lines in both of the scripts. This makes the script easier to read. The control constructs stand out from the statements within them, so it is easier to pick out the alternative paths through the script. |
The tcsh
Here are the 'tcsh' versions of the scripts.
mac2unix:
% cat mac2unix.tcsh #!/bin/tcsh
if ("$1" == "") then echo "Usage: $0 filename" exit endif
set tmp=`./gen-tmp.tcsh` tr \\r \\n < $1 > $tmp ; mv $tmp $1
gen-tmp:
% cat gen-tmp.tcsh #!/bin/tcsh set tmp=/tmp/$uid`date +%H%M%S` echo $tmp
mac2unix2:
% cat mac2unix2.tcsh #!/bin/tcsh
if ("$1" == "") then echo "Usage: $0 filename" else set tmp=`./gen-tmp.tcsh` tr \\r \\n < $1 > $tmp ; mv $tmp $1 endif
Notice the slightly different 'if' syntax and the double equals:
if [ "$1" = "" ] thenversus
if ("$1" == "") thenand the fact that the 'then' part is on the same line for 'tcsh'.
Other differences are as already noted in the previous examples.
|
Sometimes you may require input from the user while the script is running. The Bourne shell provides the 'read' command to write a prompt to the Terminal and wait for the user to type some text. This text is then assigned to a variable and can be used throughout the rest of the script. For example: % cat input #!/bin/sh Running the script gives the following: % ./input give your name> at this point the script is waiting for me to type something then press return. Continuing: give your name> Adrian Mayo Hello Adrian Mayo It would be easy to change 'mac2unix' to ask for a filename in when none is given, instead of printing the usage message and finishing. |
Tell Me More...
|
|
TIP When calling a Unix command line or another script, it is advisable to use the full pathname, for example: /usr/bin/trinstead of trThis avoids reliance on the $PATH environment variable or the current directory. My use of './gen-tmp' is not recommended as 'mac2unix' will not run unless 'gen-tmp' is in the current directory. Alternatively, you might set up the PATH variable explicitly within your shell script to avoid problems where different Unix systems have commands in different places. |
Next Part
In Parts 9 and 10, I will continue with shell scripting, introducing case statement, loops, functions, complex conditions, and other goodies.
Until then, consider:
if [ "$1" = "" ]; thencan be used instead of :
if [ "$1" = "" ]Can you think why this should work?
Enjoy :-)
Discuss this article in the Learning Center forum
|
|
Part 8 - Shell Scripting 1 (Page 2 of 2) |
|
| Copyright © 2000-2009 Inside Mac Media, Inc. All rights reserved. | ||
| Apple assumes no responsibility with regard to the selection, performance, or use of the products or services. All understandings, agreements, or warranties, if any, take place directly between the vendors and prospective users. | ||
| Apple, the Apple logo, Mac, PowerMac G4, PowerMac G5, Xserve, Xserve RAID, PowerBook, iBook, Airport, AirPort Extreme, iMac, eMac, iLife, iMovie, iCal, iPhoto, iTunes, QuickTime, FireWire, iPod, iSight, AppleWorks, Macintosh, Jaguar, Panther, Mac OS, Mac OS X and Mac OS X Server are trademarks of Apple Computer, Inc. |