103 ■ ■ ■ CHAPTER 16 ScriptingfromtheCommandLine O ne of the advantages of working at the shell commandline is that you’re working in a shell. That sounds sort of obvious and dumb, but please bear with me; pretty much any- thing you can do in a shell script, you can also do fromthecommand line. I’ve coded many ad hoc scripts right at thecommand line. I wouldn’t recommend writing anything significant that way, but for quickies it’s just the ticket. If you start a loop or conditional, such as a while, for, or if/then statement, while working at the shell prompt, thecommandline is extended until you have finished the steps in the code block. In a traditional script, such code would customarily span several lines in a file. Here is a typical interaction with the shell when entering code directly fromthecommand line: $ while : ; do > clear > ls -lrt > sleep 3 > done Note that after the first line is entered and the Enter key is pressed, thecommandline returns a > prompt to continue the code block. You can then keep adding lines until the loop completes. Once the last line has been entered, in this case the done line, the code will begin to run. In our case, it is an infinite loop, which can be stopped by a <ctrl>-c. The following examples are formatted using more traditional indentation for the sake of readability. If you were to enter these fromthecommand line, you would see results similar to those shown above. None of the examples are particularly complex; they are just representative of what can be done fromthecommand line. A Few Examples This while loop does nothing more than create a long listing of specific files over and over while sleeping for three seconds between iterations. It is part of a set of scripts I use for 104 CHAPTER 16 ■ SCRIPTINGFROMTHECOMMANDLINE concurrent package installation on a large number of remote systems. Each concurrent installation produces its own log file that documents its progress and any issues it encounters. All log files are stored in a single directory. While watching the output of the installation loop, I can tell by the size of the log file when an installation of a specific node is complete. This saves me from having to review each log individually. Successful installations all have log files that end up being of a par- ticular size. Files of a different size stand out and show me that I need to review that log. Also, watching the growth rate of the files can convey information about how the install is progressing. A typical installation goes something like this: the install package is pushed out to the remote nodes; then the package is uncompressed on each of the remote sys- tems, where the install script is run until it completes. By watching the file size of all log files increase, I can review the status of all installations at once and generally know at which point they have arrived, as well as note any problems, without actually viewing the contents of the log files themselves. This is a representative example of the miniscript I use for this task: $ while : ; do > clear > ls -lrt install_log.* > sleep 3 > done Note that I use the -lrt switch with ls. This sorts the output by modification time, with the newest files being listed last. The following miniscript is nothing more than a series of nested for loops: $ for i in 1 2 3 4 5 6 7 8 9 > do > for j in 1 2 3 4 5 6 7 8 9 > do > for k in 1 2 3 4 5 6 7 8 9 > do > touch $i$j$k > done > done > done I’ve used this type of script to create large numbers of empty files in a directory. It is the result of an effort to test a monitor script that is supposed to send notifications in case the number of files in a directory exceeds a certain threshold. Another use for it would be to perform a task a specific number of times. In this case there are 729 files cre- ated by the 3 nested loops of 9 individual digits. In the example, I could have replaced the touch command with something that didn’t reference any of the counter variables ($i, $j, or $k). It could have easily been an echo statement repeating 729 times, but that’s just boring. CHAPTER 16 ■ SCRIPTINGFROMTHECOMMANDLINE 105 The last example is something I do fairly regularly. I often want to gather information from each system named in a list of machines. This example shows how to get the list of node names by using a command call within back-ticks (` `). A command string enclosed within back-ticks denotes not the given string, but the string obtained by evaluating thecommand string and replacing it with what is returned. $ for node in `cat some_nodelist_file` > do > if [ "$node" = "cheese" ] > then > continue > else > ssh $node uname -a > ssh $node uptime > fi > done In this case, `cat some_nodelist_file` would be replaced with an actual list of nodes originally contained in that file. The file is assumed to contain the list of nodes that are space-delimited or that appear individually on each line of the file, or a combination of both. This loop does not iterate through the file line-by-line. 1 The for loop iterates through each of the nodes. I’ve also included an if/then statement that will skip any node named "cheese" to provide an example that includes a conditional. A final trick for using these kinds of scripts efficiently is command-line recall, which is discussed in Chapter 15. If you make a mistake while typing (not unlikely when you’re working with many lines at once), you can return to the previous (mistyped) command in your history and then edit thecommand sequence using vi-style command-line editing. You can also recall a previously entered miniscript for easy modification and reuse. 1. To read a file line-by-line where the lines contain more than a single “word,” refer to Chapter 10. . 103 ■ ■ ■ CHAPTER 16 Scripting from the Command Line O ne of the advantages of working at the shell command line is that you’re working in a. pressed, the command line returns a > prompt to continue the code block. You can then keep adding lines until the loop completes. Once the last line has