Выбрать главу

What is this $2 business? What's the deal with the —)? What does set - mean? And what about Naomi? Those are all things you can look up later. Just follow the template and it all works.

(OK, if you really want to learn why all of that works, I highly recommend reading the Advanced Bash-Scripting Guide at http://www.tldp.org/LDP/abs/html.)

Here's a larger example that adds a couple additional things. First of all, it uses a function "usage" to print out the help message. An interesting thing about this function is that the "echo" lasts multiple lines. Neat, eh? Bash doesn't mind. Second, it makes sure that there are at least MINITEMS items on the command line after the options are processed. Finally, it demonstrates how to process flags that override defaults.

Please steal this code whenever you are turning a simple script into one that takes options and parameters: #!/bin/bash MINITEMS=1 function usage { echo " Usage: $0 [-d] [-a author] [-c file.txt] [-h] dir1 [dir1 ...] -d debug, don't actual run command -a author name of the author -c copyright override default copyright file -h this help message " exit 1 } # Set our defaults: DEBUG=false DEBUGCMD= AUTHOR= COPYRIGHT=copyright.txt # Process command-line arguments, possibly overriding defaults args='getopt da:c:h $*' if [ $? != 0 ] then usage fi set -- $args for i do case "$i" in -h) usage shift ;; -a) AUTHOR="$2"; shift shift ;; -c) COPYRIGHT="$2"; shift shift ;; -d) DEBUG=true shift ;; --) shift; break;; esac done if $DEBUG ; then echo DEBUG MODE ENABLED. DEBUGCMD=echo fi # Make sure we have the minimum number of items on the command line. if $DEBUG ; then echo ITEM COUNT = $# ; fi if [ $# -lt "$MINITEMS" ]; then usage fi # If the first option is special, capture it: # THEITEM="$1" ; shift # Clone that line for each item you want to gather. # Make sure that you adjust the MINITEMS variable to suit your needs. # If you want to do something with each remaining item, do it here: #for i in $* ; do # echo Looky! Looky! I got $i #done if [ ! -z "$COPYRIGHT" ]; then if $DEBUG ; then echo Setting copyright to: $COPYRIGHT ; fi CRFLAG="-copyright $COPYRIGHT" fi LABEL='date -u +%Y%m%d' $DEBUGCMD mkisofs -D -l -J -r -L -f -P "$AUTHOR" -V $LABEL $CRFLAG $*

Building Up a Long Command Line

The best way to learn the Unix/Linux way of stringing commands together into one big pipe is to look over the shoulder of someone as she does it. I'll try to do that here by walking you through the steps I used to create a small utility.

Tip

Think Unix (Que) is an excellent book for learning how to link Unix/Linux tools to make bigger commands.

The single most powerful technology introduced by Unix/Linux is the ability to connect commands together like linking garden hoses. If you have one program that takes input and changes everything to uppercase, and another program that sorts the lines of a file, you can chain them together. The result is a command that converts the lines to uppercase and outputs the lines in sorted order. All you have to do is put a pipe symbol (|) between each command. The output of one command is fed into the next command: $ cat file | toupper | sort

For those of you unfamiliar with Unix/Linux, cat is the command that outputs a file. toupper is a program I wrote that changes text to uppercase. sort is the program that sorts lines of text. They all fit together quite nicely.

Let's use this to write a more complicated utility. How about a program that will determine which machine on your local network is most likely to be infected with a worm? We'll do it in one very long pipeline.

Sound amazing? Well, what this program will really do is find the hosts most likely to be infected—i.e., generate a list of which hosts require further investigation. However, I assure you that this technique will amaze your coworkers.

It's no replacement for a good malware or virus scanner. However, I picked this example because it is a good demonstration of some rudimentary shell-programming techniques, and you'll learn something about networking, too. When we're done, you'll have a simple tool you can use on your own network to detect this particular problem. I've used this tool to convince management to purchase a real virus scanner.

What's one sign that a machine is infected with some kind of worm? How about a quick test to see which machines are ARPing the most?

Spyware/worms/virii often try to connect to randomly selected machines on your network. When a machine tries to talk to a local IP address for the first time, it sends an ARP packet to find out its Ethernet (MAC) address. On the other hand, normal (uninfected) machines generally talk to a few machines only: the servers they use and their local router. Detecting a machine that is sending considerably more ARP packets than other machines on the network is often a sign that the machine is infected.

Let's build a simple shell pipeline to collect the next 100 ARP packets seen on your network and determine which hosts generated more ARP packets than their peers. It's sort of a "most likely to ARP" award. The last time I did this on a 50-host network, I found 2 machines infested with worms.

These commands should work on any Unix/Linux or Unix-like system. You will need the tcpdump command and root access. The command which tcpdump tells you if you have tcpdump installed. Sniffing packets from your network has privacy concerns. Only do this if you have permission.

Here's the final command that I came up with (sorry to spoil the surprise): $ sudo tcpdump -l -n arp | grep 'arp who-has' | head -100 | \ awk '{ print $NF }' |sort | uniq -c | sort -n

The command is too long to fit on one line of this book, so I put a backslash at the end of the first part to continue it across two lines. You don't have to type the backlash, and you shouldn't press Enter in its place.

The output looks like this: tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on en0, link-type EN10MB (Ethernet), capture size 96 bytes 1 192.168.1.104 2 192.168.1.231 5 192.168.1.251 7 192.168.1.11 7 192.168.1.148 7 192.168.1.230 8 192.168.1.254 11 192.168.1.56 21 192.168.1.91 30 192.168.1.111 101 packets captured 3079 packets received by filter 0 packets dropped by kernel

Ignore the headers. The middle lines show a count followed by an IP address. During my experiment, host 192.168.1.111 sent 30 ARP packets, while 192.168.104 only sent 1. Most machines rarely ARPed in that time period, but two hosts had four to six times as many ARPs as some of the other machines! Those were my two problem children. A quick scan with some anti-virus software and they were as good as new.