IT 244 – Chapter 8 The Bourne Again Shell: The system we are using is sf05.users.cs.umb.edu (accessible with ssh from home). This is a Linux system. Startup Files: o The shell will look for the first of the following for environment setup: ~/.bash_profile ~/.bash_login ~/.profile o Other setup files exist for interactive/non-interactive shells, but we will not be covering these. o Startup files are the first example of bash programming that we will do. The topics include: Variables Conditional Statements Functions ??? o Running a startup file other than at login – the following will cause the actions specified in the file to affect the current shell, rather than forking a new process (no need to be executable): Use the ‘.’ (dot) operator, or Use the “source” command Commands: o Symbol commands: () – subshell the content is executed in a separate process space $() – command substitution same as ``, but able to be nested (()) – arithmetic evaluation like let – the enclosed expression must include an equal “=” sign. $(()) – arithmetic expansion no equal sign is used – this is used to substitute the result of the expansion into another expression or into a string [] – test command returns a boolean result, so can be used as the condition of an if statement, or on its own after which you would test the $? Variable make sure to leave whitespace between this and the actual test to be evaluated inside it. [[]] – conditional expression like [] but adds ability to do string comparisons More about redirecting o < filename – redirects standard in from filename. o > filename – redirects standard out to filename. If filename exists and noclobber is set, this will not work If filename exists and noclobber is not set, then filename will be overwritten. If filename does not exists, then filename is created. o >| filename – redirects standard out to filename, even if noclobber is set. o >> filename – redirects standard out and appends it to filename. If filename exists and noclobber is set, this will not work If filename exists and noclobber is not set, then filename will be appended to. If filename does not exists, then filename is created. o &> filename – redirects BOTH standard out and error to filename. A Simple Shell Script o Needs to be executable as long as it is not an environment script that will be run with the ‘.’ (dot) or “source” commands. chmod 755 <file> NOTE: if you just type /bin/bash <file> then it is not necessary for the file to be executable (this is slower than the other way). o Needs to be in the $PATH, or use absolute/relative path to reference. o #!<full path to shell> - (#!/bin/bash) Directive referencing the appropriate shell executable Need this so that there is never a question as to which shell it is written for, and therefore which should run it. o # - Comment to end of line o Executing a shell script causes the current shell to fork, which creates a new process (so that one becomes two). The new process is initially a copy of the parent shell. The parent shell then tries to exec the script as a command. If it were a binary executable, then it would be overlaid in the duplicate process space and then run. Since it is a script, exec will fail, and this tells the parent shell it’s a script and the shell should exec commands in the script one by one into the duplicate process space. o This is basically the same as running each command from the command line, but the input passing the commands in is from the script. o Separating and grouping commands: ‘;’ or NEWLINE separate commands. ‘\’ continues a command on the next line The newline for the continuation will be ignored. o Both lines will be treated as one, with no added space. For bash, a newline in the middle of a quoted string acts the same way, except that it interprets the newline as a newline. ‘|’ and ‘&’ separate commands and do something else ‘|’ – pipe is as we know it, a connector of standard out to standard in. ‘&’ – backgrounding one command, followed by whitespace of any kind, allows for another command to be entered. o Therefore, the following is legal, and creates three separated processes in background: ls & ls & ls & () – groups commands and creates a subshell (another duplicate process that will be exec’ed upon). Within this grouping, commands are again separated by ‘;’, ‘|’, or ‘&’, or can be another (nested) grouping. Parameters and Variables: o Parameters are named values that can be accessed from within a script by preceding the name with a ‘$’. o Parameters whose names consist only of letters, digits, and underscores, are often called Variables. o Users can define their own variables for use during the run of a script. User defined variables can also be used as environment settings. o Setting variables: Local/temporary: <varname>=<value> NOTE: no whitespace either side of the ‘=’. Bash allows for putting variable assignments on a command line. You create the assignment before the command is called, and when the command is called the variable will be accessible. o Keyword Variables: Have special meaning to the shell and usually have short mnemonic names. (PATH, HOME, etc.) o Positional parameters: $? – gives the return status of any command. This allows for testing whether a command ran well or had an error, before going ahead and running the next command. Such testing can be used to either terminate the script, cause the script to prompt the user for information, or cause the script to make a decision on the next action. $# - gives the number of arguments passed to the script. $<num> - command line argument to a script $0 is the command name $1 to $9 are the arguments passed to the script If more than 9 arguments are passed to the script: o shift must be used to access more than 9 arguments by shifting the list or values currently referenced by the 9 variables to the left, which drops the current value of $1, and moves $2 to $1, all the way up to moving $9 to $8, and then moving the next unreferenced argument value as the value of $9. o User-created variables: Parameter substitution: If a variable is referenced (with $) as part of a command line, or as part of a string (within double quotes), the shell will interpret that variable and substitute its value, on the command line or within the string, in place of the variable name. o This can be done for all variables, user-defined or not. If whitespace must be part of a string, the string must be quoted so that all whitespace is kept. o NOTE: For parameter substitution, if whitespace exists inside a string variable, and that variable is passed to a command on the command line, the content of the variable will be substituted for the variable name, and THEN, the shell will interpret the line, which means that the separate (whitespace-separated) tokens of the string will be passed in to the command rather than one string. To pass the original string to the command, you must surround the variable name with double quotes, ie: echo “$string_with_whitespace” Assigning pathname expansion to a variable: list=max* o The shell will expand max* to all files in the current directory that start with the string max. It will then give that expanded list, as one spaceseparated string, as content of the variable list. o To echo this variable will display something like the display given by the command: ls max* (except that if any of the files is a directory, ls will list the files inside of that directory). unset <varname> Will remove the variable from the environment o ${<var>} – This is the regular way to reference the value of a variable, but $var is allowed by the bash shell. This method of retrieving the value is very useful when you are trying to substitute the value into a string where the variable name would end just before the next non-whitespace character of the string, ie: echo “$varThis is fun” – will look for a variable named varThis, when you meant the variable named var. echo “${var}This is fun” – will find the variable named var and substitute that just before the word This. Variable Attributes: o readonly <varname>=<value> - creates a readonly variable NOTE: you cannot create the readonly variable with no value, and the set its value on the next line. It MUST be given its value at the time it is created if created with the keyword readonly. o Export <varname>=<value> - creates a global variable A global variable is accessible by any command or function in this shell or any child of this shell. o Other ways to create variables with special attributes: declare and typeset both do the same thing declare <options> <varname> o Options (the first three are exclusive of each other): -a - array -f - function -i - integer -r - readonly -x – exported o If use the + character instead of – for the option, you will remove the attribute on the variable. o Special (keyword) Variables HOME PATH PS1 – User prompt PS2 – User secondary prompt (continuation) PS3 – Prompt for select command PS4 – Prompt for bash debugging option IFS – Internal Field Separator (one ore more characters) Defines the default separator, which is normally whitespace (space, tab, newline). This is the separator that the shell uses to split the command line. o Try: IFS=”:”; this=hello:::there; echo $this; cat $this CDPATH – allows for giving subdirectories and these will all be searched if the subdirectory has not yet been found. More on Processes: o Just as there is a ps command to show all processes: There is a pstree to show the tree of child processes from init which is the process with id 1. (pstree –p shows process ids). Job Control revisited: o When you use Ctrl-Z on a running process, the process is suspended. You must then type bg <job#> to resume it in background. History o List of preceding commands (events) kept for quick re-entry o Variables: HISTSIZE – the number of preceding events that will be remembered for this session (default 500 events). HISTFILE – the file that keeps the preceding commands (default !/.bash_history) HISTFILESIZE – the number of preceding events that will be remembered between sessions (default 500 events). o Re-execution history – gives the list of the whole history file history <num> - gives the last num worth of the history file. fc (fix command) -l – shows the last 16 commands -l [first [last]] – shows the commands between the given range, or from the given first to the most recent. -l [firststring [laststring]] – same but with strings that start the command line. -e <editor> - Use this editor o If FCEDIT is set, then –e is not necessary o If FCEDIT is not set, then without –e nothing happens unless an first/last is given. o NOTE: after an edit, a ‘q’ doesn’t stop the commands from running. The only way is to clear the whole buffer and save it. -s – runs without editing in the case that FCEDIT is given. !<number> - re-executes the command with history number <number>. !-<number> - re-executes the command <number> commands back. !<string> - re-executes the first previous command starting with the given string. !?<string>[?] – re-executes the first previous command containing the given string. The final ? is optional. !! – executes the last run command !# - anywhere in the current command line will duplicate the current command line. ls; !# !# !# !# !# !# I will not be going over the word designators, but they are interesting and you should take a look. o The Readline Library Configuration by creating/editing the ~/.inputrc file. If you don’t want readline being used, then start bash using the –-noediting option. set –o vi / set –o emacs setting the editor for the readline library Many of the keystrokes that you can do in vi can be done on the single command line after an <esc>. / - will do searches the same way Arrows work the same way, as do the letter keys <num><Shift-G> will go to the history line try it out Command completion – tab completes according to the PATH variable. Pathname completion – tab completes according to the path or filename given. Variable completion – tab completes according to the variables in the current environment, with the variable preceded by $. Aliases o Alias [name=[value]] – no spaces allowed either side of the = sign. o Variables in aliases – surround the alias string (including the variable preceded by a $) with single quotes. Double quotes allows the shell to expand the variable at the time the alias is being created, so the alias does not contain a variable as a result. Single quotes does not expand, so the alias string contains a variable which gets expanded at the time the alias is run. The Directory Stack: o Allows for very fast movement between commonly used directories. dirs – Displays the current stack. pushd <directorypath> – Puts the given directory (absolute or relative path) on top of the directory stack and changes the shell’s working directory to that directory. pushd with no argument will act like “cd –“. pushd +<num> - Accesses another directory on the stack other than the top directory, moves that to the top, and changes the shell’s working directory to that directory. o NOTE: the topmost directory on the stack is numbered 0, and increments on down the stack. popd – Removes the topmost entry on the stack and changes the shell’s working directory to that directory. popd +<num> - removes another directory on the stack other than the top directory. o NOTE: with a +<num> argument, popd will not change to that directory, but will only remove it from the stack. Functions o Like calling a script, but there much faster, and no overhead of forking a subshell. o Functions that are declared on the command line can be removed by giving the unset command the function name. [function] function-name() { commands commands } o Commands in a function can be anything you could have in a shell script, or a call to a function. o The break statement terminates the function before it has ended. o Functions are good for: Cleaning up code by giving names to smaller amounts of code that can be called from anywhere inside the shell script. Allows for breaking the script up into logical units. Creating your own commands by defining functions in your startup script so that they are available during your shell session. Bash features and options o set [+|-]o <feature> - on/off o shopt –[s|u] <feature> - set/unset Pages 331 through 333 gives a pretty good list. Some are controlled by set, and others by shopt. Shopt has a –o option that allows for setting features otherwise done using set. o Features: noclobber allexport (off by default) history (on by default) emacs as line editor (default is no line editing) vi as line editor (default is no line editing) Processing the command line o The following order is used in processing the command line: Bash reads the entire command before processing it If the command is multi-line, bash will recognize this and wait until it has read all the lines of the command before processing. History Expansion !<string>, or !! will cause the command line to expand into the matched command line in history. Alias Substitution If the first word of a simple command matches an alias in the environment, that alias is substituted instead of that word. o shopt –u expand_aliases turns aliases off Parsing and Scanning the command line The shell the parses the command line separating tokens by the IFS characters. o NOTE: If IFS is unset, the bash shell using spacetab-newline as its default. o The shell then scans each token for special characters and patterns for further expansion. This is command line expansion. Command line Expansion Brace Expansion o On by default – turn it off with set +o braceexpand. o Echo chap_{one,two,three}.txt becomes chap_one.txt chap_two.txt chap_three.txt o The comma-separated brace list is expanded into a space-separated list of strings. The preamble and postscript are attached to each expanded instance from the list. o Can be used for copying files with long names where most of the name is the same. o Can be used to created directories that are mostly the same. This is a good situation where no files exist for filename expansion to occur. You cannot create new names using the [ ] ambiguous file reference. Tilde Expansion o For a word starting with a tilde, the shell looks passed the tilde to find either an IFS character or a /. The / must come directly after the ~. If the ~ is followed by an IFS character or is directly followed by a /, the expansion is to the current user’s full path home directory. If the ~ is followed by a string and then an IFS character, the string is taken to be a user name, and the shell will attempt to expand the ~ with that user’s full path home directory. If this ~<string> is followed by a /, the shell will give an error message. ALSO: ~+ means PWD, and ~- means OLDPWD Parameter and variable expansion o When a $ is found, it must be followed by a string, or by one of the allowed system-level parameter character sets, terminated by an IFS character. Arithmetic expansion o If the $ is followed by ((, then arithmetic expansion takes place. (Command substitution with $() is dealt with below). The shell searches for the next )), and treats the embedded string as an arithmetic statement and gets evaluated. All Arithmetic in bash is integer. Variable names in an arithmetic expression do not need a $ preceding. The result of the expansion is substituted in the place of the $(()) expression. You can use command substitution inside an arithmetic statement, as long as the result of the command is a string that can be converted to an integer. o The let command can also be used to evaluate an arithmetic expression for an assignment to a variable let “numpages=$(wc –l < ltr.txt)/66 + 1” here, the quotes keep the expression from being broken into tokens because of the spaces. Command substitution o $() or ` ` (the second one is older, and doesn’t allow for nesting and needs to be escaped in some cases) echo $(pwd) same as echo `pwd` This script: where=$(pwd) echo “You are in $where” Or just echo “You are in $(pwd)” echo “You are in `pwd`” ls –l `find . –name README –print` o See page 341 for a nested example Word Splitting o All of the results of the above expansions can possibly be further split using IFS characters. Pathname expansion o Finally, after all of the above, the shell looks for ambiguous file references (*, ?, [ ]) If no file with the given pattern is found, the pattern is left as it is. Ambiguous file expansion will end up with either the unexpanded pattern, or a list of one to many non-ambiguous filenames, each starting with the given directory if one was given. NOTE: a period starting a filename, or following a / must be matched explicitly. o Quotation marks are used to save spaces, and in the case of single quotes, to stop expansion of special characters. If a variable has been created with special characters in it, using that variable on the command line without double quotes will cause the special characters to be expanded. Process substitution o Finally, the shell is able to process the |, >, and < redirection operators for process substitution. o This means that the shell substitutes the input and output devices according to pipes After all these expansions have been completed, the shell removes from the tokens any single/double quotations, and backslashes that didn’t result from an expansion.