Unix shell grab bag

March 6, 2009 | by Tim

Largely for my own reference, here are some Unix shell tricks that have come up lately. If you’re using Linux, Mac OS X, or other Unix-like systems, these might be handy.

Redirecting output

When a process starts, it opens three file descriptors: file descriptor 0 for standard input (STDIN), file descriptor 1 for standard output (STDOUT), and file descriptor 2 for standard error (STDERR). By default, the standard output and error just print to the terminal (so you see them on the screen), but you can redirect them to a file (e.g. for logging or just to cut down on gibberish that you’re not going to read anyway) by using “>” to create/overwrite the file or “>>” to create/append the file.

I’ve used “find /” as the command in these examples because it takes a while to run and tends to produce plenty of output on STDOUT and STDERR.


# Redirect STDOUT to a file, but leave STDERR to print on screen.
# If the file exists, overwrite it.
$ find / > /some/file.txt
# Redirect STDOUT to a file, but leave STDERR to print on screen.
# If the file exists, append to the end of it. If it doesn't exist, create it.
$ find / >> /some/file.txt
# Redirect STDOUT to the null device, which is a special file that silently discards everything.
# Use this if you want to ignore STDOUT but keep an eye on STDERR.
$ find / > /dev/null
# Redirect both STDOUT and STDERR to the same file.
$ find / > /some/file.txt 2>&1
# Redirect STDOUT and STDERR to different files.
# The numbers refer to the file descriptors mentioned above.
$ find / > /path/to/log.out 2>/path/to/log.err
# ... or, more explicitly:
$ find / 1>/path/to/log.out 2>/path/to/log.err

Background processes

Often you’ll want to start something running and keep working on something else. This is frequently done by redirecting the output to a file (or the null device) by starting it in the background with the “&” keyword.


# Start a process in the background.
$ find / &
# Start a process in the background and ignore all output.
$ find / > /dev/null 2>&1

To bring a background process back to the foreground, for example to stop it with ctrl+c or to provide input if it asks a question, use the “fg” command.

If you start several background processes, use the “jobs” command to list them. That will print the job number (different from the process ID) that you can use to bring a specific one back to the foreground with e.g. “fg 3″ to bring back job 3.


$ find / > /dev/null 2>&1 &
$ cp file.dat /mnt/other_drive &
$ sleep 600 &
$ jobs
[1] Running find / > /dev/null 2>&1 &
[2]- Running cp file.dat /mnt/other_drive &
[3]+ Running sleep 600 &
$ fg 3
sleep 600

Capturing process ID for simple start/stop scripts

Putting those together, here’s a simple start/stop script that starts a command in the background and stores all output in a log file. It also uses the “$!” variable to record the process ID so it can kill the process later. Call the file “startstop.sh” and just run “startstop.sh start” to start it and “startstop.sh stop” to stop it.


#!/bin/sh
PID_FILE="test.pid"
LOG_FILE="test.log"
CMD="find /"
if [ "$1" == "start" ]; then
echo "starting!"
$CMD > $LOG_FILE 2>&1 &
echo $! > $PID_FILE;
fi
if [ "$1" == "stop" ]; then
echo "stopping!"
kill `cat $PID_FILE`;
rm $PID_FILE;
fi

Bookmark and Share

Tags:

Leave a Reply