Monthly Archives: September 2009

Mac OS X Bag of Tips

Every day, I spend most of my work hours at the OS X terminal. Consequently, I accumulated a few tips and tricks I would like to share with the readers.

Selecting Text

  • To select a word, double click on that word. The terminal is smart enough to discern when the period acts as a sentence terminator and when it is part of a file name. In the later case, the whole file name is selected. After double clicking and before releasing the mouse button, the user can drag the mouse to select additional words
  • To select a line, triple click on that line and drag the mouse up or down to select additional lines
  • To select space-delimited text, hold down Command and Shift and double click on the text. This action is useful for select path names. If the path name contains one or more spaces, drag the mouse to select the rest
  • If the user holds down the Command and Shift keys and double click a URL, OS X will open that URL in the default browser
  • If the user holds down the Option key, the mouse pointer will change to a cross hair for selecting column of text. An example of this application is for selecting the output of the ls command

Windows Management

  • The Command+1 combination will bring the focus to the first window, Command+2 to the the second and so on.
  • The Command + left/right arrows switch between terminal windows
  • Like other OS X applications, the Command + ` also switches between windows
  • The Shift + Command + [ or ] combo switch between different tabs
  • The Command + up/down arrows scroll through the window’s buffer, one line a time; the page up/down keys scroll one screen.
  • The Window > Split Pane menu or Command + D will split the window into two panes–useful for scrolling back to review previous text and/or select them

Saving a Transcript

  • To save the plain text transcript of all interactions since the window opened, click on the Shell > Export Text As… menu
  • To save the PDF transcript, click on the Shell > Print…, click the PDF button and select the appropriate choice

Window Group

I usually open two windows and arrange them side by side. Window group is a nice feature which helps me defining a group of windows for later use. To define a window group, first open as many windows as you would like and arrange/resize them. Next click the Window > Save Windows As Group… menu and give it a name. The “Use window group when Terminal starts” check box is self-explanatory.

Conclusion

These are just a handful of tricks that I can remember. I am sure the Terminal has more up its sleeve, waiting for us to discover. If you know a trick, please feel free to comment.

Advertisements

Quick and Dirty Way to Parse Command Line in a Bash Script

The Problem

I want a quick and dirty way to parse command line from my bash script. For example:

	myscript.sh --file foo.txt --width 72

The Solution

The method is truly quick and dirty, but before we dive right in, let’s make a few assumptions:

  • Each flag must be followed by a value. That means –debug 1 is fine, but –debug is not
  • The flag name will become the variable name. For example, –file foo.txt will result in a variable $file which has value foo.txt
  • The function does not check or validate the variables in any way. It’s a GIGO (garbage in, garbage out) situation
  • Flags can have one- or two-dash: -debug is the same as –debug

With that in mind, let’s take a look at the function

# file: getopt_simple.sh
function getopt_simple()
{
    until [ $# -eq 0 ]
    do
        eval ${1##*-}='$2'
        shift 2
    done
}

Below is a sample script which make use of this function

#!/bin/sh

# file: getopt_simple_tryout
# Try out the simple getopt function

# Include the function
source getopt_simple.sh

# Simulate the command line
set -- --file myfile.txt -depth 3 -width 72 --name "Hai Vu"

# Parse the command line
getopt_simple "$@"

# Now show the variables
echo "file  = $file "
echo "depth = $depth"
echo "name  = $name "

Here is its output:

	$ getopt_simple_tryout.sh 
	file  = myfile.txt 
	depth = 3
	name  = Hai Vu 

Explanation

  • Line 4: Loop until we exhaust the parameters on the command line
  • Line 6: The ${1##*-} expression strips the preceding dashes (-) from $1. We treats $1 as the name of the variable and $2 as its value
  • Line 7: Move to the next pair of parameters

Conclusion

This function does not do any checking or validation at all, but it is short and sweet–good for those times when you need to try something out quickly

Parse Command Line in a Tcl Script

The Problem

I am writing script in Tcl, but want an easy and simple way to parse command line parameter. For example, the user might invoke my script as:

	tclsh myscript.tcl -server testserver15 -user testuser3

The Solution

This is one way to solve the problem. It does not mean to be the only one, but an easy and simple one. The solution is to use a library package called cmdline which comes with most Tcl installations. Below is a sample script I wrote to demonstrate this technique.

The Sample Script

To demonstrate the solution, I created a sample script called parse_argv.tcl with the following contents:

package require cmdline

# Show argv before processing
puts "Before, argv = '$argv'"

# Process the command line
set parameters {
    {server.arg ""   "Which server to test"}
    {port.arg   5551 "Port to send test cmd"}
    {user.arg   ""   "Login name"}
    {debug           "Output extra debug info"}
}
array set arg [cmdline::getoptions argv $parameters]

# Verify required parameters
set requiredParameters {server user}
foreach parameter $requiredParameters {
    if {$arg($parameter) == ""} {
        puts stderr "Missing required parameter: -$parameter"
        exit 1
    }
}

# Displays the arguments
puts ""
parray arg
puts ""

# Show argv after processing
puts "After, argv = '$argv'"

Explanation

  • Line 7 – Define the command line parameters and their defaults. If a parameter has an .arg suffix, then it must be followed by a value. A parameter without the .arg suffix is a simple boolean (0 or 1) parameter. Please note that the parameter names are case sensitive, so -server is not the same as -Server.For more information, please consult the documentation for cmdline.
  • Line 8 – A call to cmdline::getoptions does all the works. Please note:
    1. If the user supplies a parameter not that getoptions does not recognize, it will display a usage and throw an error, which will cause the script to exit prematurely.
    2. If getoptions encounters a ‘–‘ (double dashes) on the command line, it will delete that token and stop processing. This behavior is consistent with many Unix’s commands.
    3. The contents of argv will be modified. That is why we pass argv instead of $argv to getoptions.
    4. getoptions returns a list of keyword/value such as {server “” port 5551 …}. The array set turns this list into an array.
  • Line 30 – After processing the command line, argv contains the left-over. Please take a look at the Sample Runs section for an example of this behavior

Sample Runs

	$ tclsh parse_argv.tcl 
	Before, argv = ''
	Missing required parameter: -server

Invoke the script without specifying the required parameters will cause it to show an error then exit.


	$ tclsh parse_argv.tcl -server testserver15 -user testuser3 extra1 extra2
	Before, argv = '-server testserver15 -user testuser3 extra1 extra2'

	arg(debug)  = 0
	arg(port)   = 5551
	arg(server) = testserver15
	arg(user)   = testuser3

	After, argv = 'extra1 extra2'

In this run, the user specifies all the required parameters and a few extras. Notice:

  • How argv changed after calling getoptions
  • arg(debug) is 0 because the user has not specified a -debug flag in the command line

Conclusion

The cmdline package offers a simple and easy way to parse command line parameters. It should save programmers coding time and sanity. The package is not perfect: it does not check for required parameters, nor does it validate them. In the script, I worked around the first issue by checking for required parameters myself (lines 16 to 22).

To demonstrate the second issue, let’s take a look at the -port parameter. If I require this parameter to be an integer between 5000-5999, I have to write the verification myself.

I hope cmdline to evolve and address these issues. Meanwhile, I am glad to have it under my belt.

Share Your Printer in Snow Leopard – How To

This tutorial solves the following problem: the user wants to print to a printer attached to another Mac.

Open the System Preferences

media_1252769931991.png

Click on the Apple menu at the top left corner of your screen, then click on "System Preferences"

Open Print & Fax

media_1252769994132.png

Locate and click on this icon

Turn on Sharing

media_1252770020623.png

(1) Click on the printer you want to share, then (2) Turn on the share check box.

On the other computer, add a printer and you will find this printer in the list of shared printers.

Simple Menu with Bash’s Select Command

The Problem

Sometimes, I need a simple menu in bash, but I don’t want to spend a good deal of time coding for one.

The Solution

Bash has a built-in command called select which gets the job done. To demonstrate this command, I am going to write a short bash script. This script lists all the files in the current directory, then prompts the user to make a choice. If the choice is valid, it invokes the editor on the file. It will ignore any invalid choice. Below is the source for that script:

#!/bin/sh
# Displays a list of files in current directory and prompt for which
# file to edit

# Set the prompt for the select command
PS3="Type a number or 'q' to quit: "

# Create a list of files to display
fileList=$(find . -maxdepth 1 -type f)

# Show a menu and ask for input. If the user entered a valid choice,
# then invoke the editor on that file
select fileName in $fileList; do
	if [ -n "$fileName" ]; then
		vim ${fileName}
	fi
	break
done

Explanation

Line 6 – By default the select commmand uses ‘#?’ as a menu prompt. If the variable PS3 is defined, it will use that variable instead.

Line 9 – The find command retrieves a list of files in the current directory. The script then stores the result in the variable fileList

Line 13 to 18 – The select .. do .. done command displays a menu using $fileList as a list of items.

Line 14 to 16 – This block of code check if the user’s choice was valid and invoke the editor accordingly

Line 17 – The select command acts like an endless loop unless a break command is encountered

Sample Run

Below is a sample run

	$ edit_files.sh
	1) ./arguments		        
	2) ./data		            
	3) ./for_example	        
	4) ./getopt_function.sh	   
	5) ./getopt_homemade.sh	   
	6) ./getopt_tryout
	Type a number or 'q' to quit: 3

The Hack

If you are reading this far, I hope you detected my hack (hint, look at the PS3 prompt). By experimenting with select, I found out that if the user entered an invalid choice (i.e. a letter ‘q’ instead of an integer) then select will set the control variable ($fileName in this case) to empty. Taking advantage of this feature (or bug?), I designed the prompt and check for non-empty variable (line 14-16) before invoking the editor.

Conclusion

The select command is easy to use, but it save the script writers from the tedious job of displaying the menu, the prompt, then ask for the user’s input. The only caveat programmers need to watch out for is the lack of input validation so be sure to check your control variable before using it.

Changing Directory Listing (ls) in RHEL

This is a follow-up to my previous post.

The Problem
The ls command in Redhat Enterprise Linux (RHEL) by default uses the dark blue to show directories. This color is hard to see, especially on laptops with dim screens. I would like an easy way to change that.


The Solution

The solution is similar to that in my previous post, but Redhat makes it a little easier. Here are the steps:

  1. Create a text file containing the color definitions by issue the following command: dircolors > ~/.dircolors
  2. Edit the file ~/.dircolors and change the colors to your taste
  3. Exit the shell and login again to see the changes

Explanation

When a user logs in, RHEL executes the start-up files in the /etc/profile.d directory. Among those start-up files, colorls.sh (for borne-family shells) and colorls.csh (for csh-family shells) are responsible for setting the ls colors. The scripts look in the user’s home directory for a file called .dircolors to overwrite the colors. By creating and tweaking this file, the user can change the colors of the ls command to his or her taste. Personally, I prefer the bright yellow for directory: