|
Softpanorama |
May the source be with you, but remember the KISS principle ;-)
Softpanorama Search
|
| ((...)) command and let command | Arrays | Pipes in Loops | |||
| Comparison operators | Loops in Shell | Advanced navigation | Shell History | Humor | Etc |
Older UNIX shells like Borne shell have clumsy, extremely inconvenient and confusing way of doing arithmetic. When Perl arrived, it was clear the shell is an outdated crap for most system administration tasks that involve substantial calculations. So ksh93 was created to fight back the lost ground. While it failed to stop Perl, ksh93 was a big improvement, and later bash re-implemented most of the advanced features of ksh93 plus a couple of its own. The version to look for the features described is bash 3.2 or later.
First of all in BASH you can (and should) use $(( )) or let for integer arithmetic expressions. For example:
i=$(( i + 1 )) let i+=1
or
i=$(( i++)) let i++
You must not have spaces around the equals sign, as with any bash variable assignment. As long as you keep to integer arithmetic, you can use all the standard C-language operators inside of $(()). Spaces are treated as in any normal algorithmic language: they are options. But again, please be aware that space before equal sign confuses bash into thinking that this is a function invocation:
i = $(( i + 5 )) # not what you think!
In this case bash will try to run a program named i and its first argument would be an equal sign, and its second argument would be the number you get adding 5 to the value of $i.
Another oddity to these expressions is that the R-value rule ($ should be prefixed to the shell variable on the right side of assignment statement to get its value) is not applicable inside the double parentheses. But at the same time you do need the dollar sign for positional parameters (e.g.,$2) to distinguish it from a numeric constant (e.g., "2"). Here's an example:
i=$(( i + $2 ))
There is a several shortcuts supported by BASH. One is += type of operators (familiar to any programmer):
let i=i+5
can be written as
let i+=5Usual C-style increments work too:
let i++or
(( i++ ))
| Operator | Operation with assignment | Use | Meaning |
|---|---|---|---|
| = | Simple assignment | a=b | a=b |
| *= | Multiplication | a*=b | a=(a*b) |
| /= | Division | a/=b | a=(a/b) |
| %= | Remainder | a%=b | a=(a%b) |
| += | Addition | a+=b | a=(a+b) |
| -= | Subtraction | a-=b | a=(a-b) |
| <<= | Bit-shift left | a<<=b | a=(a<<b) |
| >>= | Bit-shift right | a>>=b | a=(a>>b) |
| &= | Bitwise "and" | a&=b | a=(a&b) |
| ^= | Bitwise "exclusive or" | a^=b | a=(a^b) |
| |= | Bitwise "or" | a|=b | a=(a|b) |
These assignment operators are also available with $(( )) provided they occur inside the double parentheses. The outermost assignment is still just plain old shell variable assignment.
The assignments can also be cascaded, through the use of the comma operator:
echo $(( X+=2 , Y++ ))
which will do both assignments and then echo the result of the second expression (since the comma operator returns the value of its second expression).
Unlike many other places in bash scripts where certain characters have special meanings (like the asterisk for wildcard patterns or parentheses for subshell execution), in these expressions we don't need to use quotes or backslashes to escape them since they don't have their special meaning in let statements or inside of the $(( )) construct:
let Y=(X+2)*10 Y=$(( ( X + 2 ) * 10 ))
The $(( )) syntax allows all sorts of whitespace within the parentheses. For that reason, it is both less prone to errors and makes the code much more readable and is, therefore, our preferred way of doing bash integer arithmetic. However, an exception can be made for the occasional += assignment or ++ operator, or when we get nostalgic for the early days of BASIC programming (which had a LET statement).
There are two major differences:
The ((...)) command is more convenient to use than let, because some of the arithmetic operators (like *) have special meaning to the shell. The only contract that is often used with let is inrement like in
let i++
This commands is equivalent to:
let i=i+1
and to
(( i=i + 1 ))as well as to
(( i++ ))Before the Korn shell introduced let and (( ... )) commands, the only way to perform arithmetic was with expr. For example, to do the same increment X operation using expr:
X=`expr $X + 1`
There is a similar mechanism for integer arithmetic with shell variables using the bash built-in let statement. It uses the same arithmetic operators as the $(( )) construct:
let i=i+5
When using let, there are some fancy assignment operators we can use such as this (which will accomplish the same thing as the previous line):
let i+=5The ((...)) command also can be used in any control statements. for example:
function mess
{
if (( "$1" > 0 )) ; then>
total=$1
else
total=100
fi
tail -$total /var/adm/messages | more
}
Initialization of arrays in bash has format similar to Perl:
solaris=(serv01 serv02 serv07 ns1 ns2)
Each element of the array is a separate word in the list enclosed in parentheses. Then you can refer to each this way:
echo solaris is installed on ${solaris[2]}
If you omit index writing echo $solaris you will get the first element too.
Another example taken from Bash Shell Programming in Linuxarray=(red green blue yellow magenta)
len=${#array[*]}
echo "The array has $len members. They are:"
i=0
while [ $i -lt $len ]; do
echo "$i: ${array[$i]}"
let i++
done
Run this example:
$ ./myscript.sh
The array has 5 members. They are:
0: red
1: green
2: blue
3: yellow
4: magenta
|
Please visit Heiner Steven's SHELLdorado, the best shell scripting site on the Internet |
Linux JournalIf you're used to a "standard" *NIX shell you may not be familiar with bash's array feature. Although not as powerful as similar constructs in the P languages (Perl, Python, and PHP) and others, they are often quite useful.
Bash arrays have numbered indexes only, but they are sparse, ie you don't have to define all the indexes. An entire array can be assigned by enclosing the array items in parenthesis:
arr=(Hello World)Individual items can be assigned with the familiar array syntax (unless you're used to Basic or Fortran):arr[0]=Hello arr[1]=WorldBut it gets a bit ugly when you want to refer to an array item:echo ${arr[0]} ${arr[1]}To quote from the man page:The braces are required to avoid conflicts with pathname expansion.
In addition the following funky constructs are available:
${arr[*]} # All of the items in the array ${!arr[*]} # All of the indexes in the array ${#arr[*]} # Number of items in the array ${#arr[0]} # Length if item zeroThe ${!arr[*]} is a relatively new addition to bash, it was not part of the original array implementation.
The following example shows some simple array usage (note the "[index]=value" assignment to assign a specific index):
#!/bin/bash array=(one two three four [5]=five) echo "Array size: ${#array[*]}" echo "Array items:" for item in ${array[*]} do printf " %s\n" $item done echo "Array indexes:" for index in ${!array[*]} do printf " %d\n" $index done echo "Array items and indexes:" for index in ${!array[*]} do printf "%4d: %s\n" $index ${array[$index]} doneRunning it produces the following output:Array size: 5 Array items: one two three four five Array indexes: 0 1 2 3 5 Array items and indexes: 0: one 1: two 2: three 3: four 5: fiveNote that the "@" sign can be used instead of the "*" in constructs such as ${arr[*]}, the result is the same except when expanding to the items of the array within a quoted string. In this case the behavior is the same as when expanding "$*" and "$@" within quoted strings: "${arr[*]}" returns all the items as a single word, whereas "${arr[@]}" returns each item as a separate word.
The following example shows how unquoted, quoted "*", and quoted "@" affect the expansion (particularly important when the array items themselves contain spaces):
When run it outputs:#!/bin/bash array=("first item" "second item" "third" "item") echo "Number of items in original array: ${#array[*]}" for ix in ${!array[*]} do printf " %s\n" "${array[$ix]}" done echo arr=(${array[*]}) echo "After unquoted expansion: ${#arr[*]}" for ix in ${!arr[*]} do printf " %s\n" "${arr[$ix]}" done echo arr=("${array[*]}") echo "After * quoted expansion: ${#arr[*]}" for ix in ${!arr[*]} do printf " %s\n" "${arr[$ix]}" done echo arr=("${array[@]}") echo "After @ quoted expansion: ${#arr[*]}" for ix in ${!arr[*]} do printf " %s\n" "${arr[$ix]}" doneNumber of items in original array: 4 first item second item third item After unquoted expansion: 6 first item second item third item After * quoted expansion: 1 first item second item third item After @ quoted expansion: 4 first item second item third itemMitch Frazier is the System Administrator at Linux Journal.
z=$(($z+3)) z=$((z+3)) # Also correct. # Within double parentheses, #+ parameter dereferencing #+ is optional. # $((EXPRESSION)) is arithmetic expansion. # Not to be confused with #+ command substitution. # You may also use operations within double parentheses without assignment. n=0 echo "n = $n" # n = 0 (( n += 1 )) # Increment. # (( $n += 1 )) is incorrect! echo "n = $n" # n = 1 let z=z+3 let "z += 3" # Quotes permit the use of spaces in variable assignment. # The 'let' operator actually performs arithmetic evaluation, #+ rather than expansion.
|
Please visit Heiner Steven SHELLdorado the best shell scripting site on the Internet |
Linux.com Turn Vim into a bash IDE
| Path | Description | X-ref |
|---|---|---|
| ./bashdb | Deprecated sample implementation of a bash debugger. | |
| ./complete | Shell completion code. | |
| ./functions | Example functions. | |
| ./functions/array-stuff | Various array functions (ashift, array_sort, reverse). | |
| ./functions/array-to-string | Convert an array to a string. | |
| ./functions/autoload | An almost ksh-compatible 'autoload' (no lazy load). | ksh |
| ./functions/autoload.v2 | An almost ksh-compatible 'autoload' (no lazy load). | ksh |
| ./functions/autoload.v3 | A more ksh-compatible 'autoload' (with lazy load). | ksh |
| ./functions/basename | A replacement for basename(1). | basename |
| ./functions/basename2 | Fast basename(1) and dirname(1) functions for bash/sh. | basename, dirname |
| ./functions/coproc.bash | Start, control, and end co-processes. | |
| ./functions/coshell.bash | Control shell co-processes (see coprocess.bash). | |
| ./functions/coshell.README | README for coshell and coproc. | |
| ./functions/csh-compat | A C-shell compatibility package. | csh |
| ./functions/dirfuncs | Directory manipulation functions from the book The Korn Shell. | |
| ./functions/dirname | A replacement for dirname(1). | dirname |
| ./functions/emptydir | Find out if a directory is empty. | |
| ./functions/exitstat | Display the exit status of processes. | |
| ./functions/external | Like command, but forces the use of external command. | |
| ./functions/fact | Recursive factorial function. | |
| ./functions/fstty | Front-end to sync TERM changes to both stty(1) and readline 'bind'. | stty.bash |
| ./functions/func | Print out definitions for functions named by arguments. | |
| ./functions/gethtml | Get a web page from a remote server (wget(1) in bash). | |
| ./functions/getoptx.bash | getopt function that parses long-named options. | |
| ./functions/inetaddr | Internet address conversion (inet2hex and hex2inet). | |
| ./functions/inpath | Return zero if the argument is in the path and executable. | inpath |
| ./functions/isnum.bash | Test user input on numeric or character value. | |
| ./functions/isnum2 | Test user input on numeric values, with floating point. | |
| ./functions/isvalidip | Test user input for valid IP addresses. | |
| ./functions/jdate.bash | Julian date conversion. | |
| ./functions/jj.bash | Look for running jobs. | |
| ./functions/keep | Try to keep some programs in the foreground and running. | |
| ./functions/ksh-cd | ksh-like cd: cd [-LP] [dir[change]]. | ksh |
| ./functions/ksh-compat-test | ksh-like arithmetic test replacements. | ksh |
| ./functions/kshenv | Functions and aliases to provide the beginnings of a ksh environment for bash | ksh |
| ./functions/login | Replace the login and newgrp built-ins in old Bourne shells. | |
| ./functions/lowercase | Rename files to lowercase. | rename lower |
| ./functions/manpage | Find and print a manpage. | fman |
| ./functions/mhfold | Print MH folders, useful only because folders(1) doesn't print mod date/times. | |
| ./functions/notify.bash | Notify when jobs change status. | |
| ./functions/pathfuncs | Path related functions (no_path, add_path, pre-path, del_path). | path |
| ./functions/README | README | |
| ./functions/recurse | Recursive directory traverser. | |
| ./functions/repeat2 | A clone of the C shell built-in repeat. | repeat, csh |
| ./functions/repeat3 | A clone of the C shell built-in repeat. | repeat, csh |
| ./functions/seq | Generate a sequence from m to n;m defaults to 1. | |
| ./functions/seq2 | Generate a sequence from m to n;m defaults to 1. | |
| ./functions/shcat | Readline-based pager. | cat, readline pager |
| ./functions/shcat2 | Readline-based pagers. | cat, readline pager |
| ./functions/sort-pos-params | Sort the positional parameters. | |
| ./functions/substr | A function to emulate the ancient ksh built-in. | ksh |
| ./functions/substr2 | A function to emulate the ancient ksh built-in. | ksh |
| ./functions/term | A shell function to set the terminal type interactively or not. | |
| ./functions/whatis | An implementation of the 10th Edition Unix sh built-in whatis(1) command. | |
| ./functions/whence | An almost ksh-compatible whence(1) command. | |
| ./functions/which | An emulation of which(1) as it appears in FreeBSD. | |
| ./functions/xalias.bash | Convert csh alias commands to bash functions. | csh, aliasconv |
| ./functions/xfind.bash | A find(1) clone. | |
| ./loadables/ | Example loadable replacements. | |
| ./loadables/basename.c | Return nondirectory portion of pathname. | basename |
| ./loadables/cat.c | cat(1) replacement with no options—the way cat was intended. | cat, readline pager |
| ./loadables/cut.c | cut(1) replacement. | |
| ./loadables/dirname.c | Return directory portion of pathname. | dirname |
| ./loadables/finfo.c | Print file info. | |
| ./loadables/getconf.c | POSIX.2 getconf utility. | |
| ./loadables/getconf.h | Replacement definitions for ones the system doesn't provide. | |
| ./loadables/head.c | Copy first part of files. | |
| ./loadables/hello.c | Obligatory "Hello World" / sample loadable. | |
| ./loadables/id.c | POSIX.2 user identity. | |
| ./loadables/ln.c | Make links. | |
| ./loadables/logname.c | Print login name of current user. | |
| ./loadables/Makefile.in | Simple makefile for the sample loadable built-ins. | |
| ./loadables/mkdir.c | Make directories. | |
| ./loadables/necho.c | echo without options or argument interpretation. | |
| ./loadables/pathchk.c | Check pathnames for validity and portability. | |
| ./loadables/print.c | Loadable ksh-93 style print built-in. | |
| ./loadables/printenv.c | Minimal built-in clone of BSD printenv(1). | |
| ./loadables/push.c | Anyone remember TOPS-20? | |
| ./loadables/README | README | |
| ./loadables/realpath.c | Canonicalize pathnames, resolving symlinks. | |
| ./loadables/rmdir.c | Remove directory. | |
| ./loadables/sleep.c | Sleep for fractions of a second. | |
| ./loadables/strftime.c | Loadable built-in interface to strftime(3). | |
| ./loadables/sync.c | Sync the disks by forcing pending filesystem writes to complete. | |
| ./loadables/tee.c | Duplicate standard input. | |
| ./loadables/template.c | Example template for loadable built-in. | |
| ./loadables/truefalse.c | True and false built-ins. | |
| ./loadables/tty.c | Return terminal name. | |
| ./loadables/uname.c | Print system information. | |
| ./loadables/unlink.c | Remove a directory entry. | |
| ./loadables/whoami.c | Print out username of current user. | |
| ./loadables/perl/ | Illustrates how to build a Perl interpreter into bash. | |
| ./misc | Miscellaneous | |
| ./misc/aliasconv.bash | Convert csh aliases to bash aliases and functions. | csh, xalias |
| ./misc/aliasconv.sh | Convert csh aliases to bash aliases and functions. | csh, xalias |
| ./misc/cshtobash | Convert csh aliases, environment variables, and variables to bash equivalents. | csh, xalias |
| ./misc/README | README | |
| ./misc/suncmd.termcap | SunView TERMCAP string. | |
| ./obashdb | Modified version of the Korn Shell debugger from Bill Rosenblatt's Learning the Korn Shell. | |
| ./scripts.noah | Noah Friedman's collection of scripts (updated to bash v2 syntax by Chet Ramey). | |
| ./scripts.noah/aref.bash | Pseudo-arrays and substring indexing examples. | |
| ./scripts.noah/bash.sub.bash | Library functions used by require.bash. | |
| ./scripts.noah/bash_version. bash | A function to slice up $BASH_VERSION. | |
| ./scripts.noah/meta.bash | Enable and disable eight-bit readline input. | |
| ./scripts.noah/mktmp.bash | Make a temporary file with a unique name. | |
| ./scripts.noah/number.bash | A fun hack to translate numerals into English. | |
| ./scripts.noah/PERMISSION | Permissions to use the scripts in this directory. | |
| ./scripts.noah/prompt.bash | A way to set PS1 to some predefined strings. | |
| ./scripts.noah/README | README | |
| ./scripts.noah/remap_keys.bash | A front end to bind to redo readline bindings. | readline |
| ./scripts.noah/require.bash | Lisp-like require/provide library functions for bash. | |
| ./scripts.noah/send_mail. | Replacement SMTP client written in bash. | |
| ./scripts.noah/shcat.bash | bash replacement for cat(1). | cat |
| ./scripts.noah/source.bash | Replacement for source that uses current directory. | |
| ./scripts.noah/string.bash | The string(3) functions at the shell level. | |
| ./scripts.noah/stty.bash | Front-end to stty(1) that changes readline bindings too. | fstty |
| ./scripts.noah/y_or_n_p.bash | Prompt for a yes/no/quit answer. | ask |
| ./scripts.v2 | John DuBois' ksh script collection (converted to bash v2 syntax by Chet Ramey). | |
| ./scripts.v2/arc2tarz | Convert an arc archive to a compressed tar archive. | |
| ./scripts.v2/bashrand | Random number generator with upper and lower bounds and optional seed. | random |
| ./scripts.v2/cal2day.bash | Convert a day number to a name. | |
| ./scripts.v2/cdhist.bash | cd replacement with a directory stack added. | |
| ./scripts.v2/corename | Tell what produced a core file. | |
| ./scripts.v2/fman | Fast man(1) replacement. | manpage |
| ./scripts.v2/frcp | Copy files using ftp(1) but with rcp-type command-line syntax. | |
| ./scripts.v2/lowercase | Change filenames to lowercase. | rename lower |
| ./scripts.v2/ncp | A nicer front end for cp(1) (has -i, etc).. | |
| ./scripts.v2/newext | Change the extension of a group of files. | rename |
| ./scripts.v2/nmv | A nicer front end for mv(1) (has -i, etc).. | rename |
| ./scripts.v2/pages | Print specified pages from files. | |
| ./scripts.v2/PERMISSION | Permissions to use the scripts in this directory. | |
| ./scripts.v2/pf | A pager front end that handles compressed files. | |
| ./scripts.v2/pmtop | Poor man's top(1) for SunOS 4.x and BSD/OS. | |
| ./scripts.v2/README | README | |
| ./scripts.v2/ren | Rename files by changing parts of filenames that match a pattern. | rename |
| ./scripts.v2/rename | Change the names of files that match a pattern. | rename |
| ./scripts.v2/repeat | Execute a command multiple times. | repeat |
| ./scripts.v2/shprof | Line profiler for bash scripts. | |
| ./scripts.v2/untar | Unarchive a (possibly compressed) tarfile into a directory. | |
| ./scripts.v2/uudec | Carefully uudecode(1) multiple files. | |
| ./scripts.v2/uuenc | uuencode(1) multiple files. | |
| ./scripts.v2/vtree | Print a visual display of a directory tree. | tree |
| ./scripts.v2/where | Show where commands that match a pattern are. | |
| ./scripts | Example scripts. | |
| ./scripts/adventure.sh | Text adventure game in bash! | |
| ./scripts/bcsh.sh | Bourne shell's C shell emulator. | csh |
| ./scripts/cat.sh | Readline-based pager. | cat, readline pager |
| ./scripts/center | Center a group of lines. | |
| ./scripts/dd-ex.sh | Line editor using only /bin/sh, /bin/dd, and /bin/rm. | |
| ./scripts/fixfiles.bash | Recurse a tree and fix files containing various bad characters. | |
| ./scripts/hanoi.bash | The inevitable Towers of Hanoi in bash. | |
| ./scripts/inpath | Search $PATH for a file the same name as $1; return TRUE if found. | inpath |
| ./scripts/krand.bash | Produces a random number within integer limits. | random |
| ./scripts/line-input.bash | Line input routine for GNU Bourne Again Shell plus terminal-control primitives. | |
| ./scripts/nohup.bash | bash version of nohup command. | |
| ./scripts/precedence | Test relative precedences for && and || operators. | |
| ./scripts/randomcard.bash | Print a random card from a card deck. | random |
| ./scripts/README | README | |
| ./scripts/scrollbar | Display scrolling text. | |
| ./scripts/scrollbar2 | Display scrolling text. | |
| ./scripts/self-repro | A self-reproducing script (careful!). | |
| ./scripts/showperm.bash | Convert ls(1) symbolic permissions into octal mode. | |
| ./scripts/shprompt | Display a prompt and get an answer satisfying certain criteria. | ask |
| ./scripts/spin.bash | Display a spinning wheel to show progress. | |
| ./scripts/timeout | Give rsh(1) a shorter timeout. | |
| ./scripts/vtree2 | Display a tree printout of the direcotry with disk use in 1k blocks. | tree |
| ./scripts/vtree3 | Display a graphical tree printout of dir. | tree |
| ./scripts/vtree3a | Display a graphical tree printout of dir. | tree |
| ./scripts/websrv.sh | A web server in bash! | |
| ./scripts/xterm_title | Print the contents of the xterm title bar. | |
| ./scripts/zprintf | Emulate printf (obsolete since printf is now a bash built-in). | |
| ./startup-files | Example startup files. | |
| ./startup-files/Bash_aliases | Some useful aliases (written by Fox). | |
| ./startup-files/Bash_profile | Sample startup file for bash login shells (written by Fox). | |
| ./startup-files/bash-profile | Sample startup file for bash login shells (written by Ramey). | |
| ./startup-files/bashrc | Sample Bourne Again Shell init file (written by Ramey). | |
| ./startup-files/Bashrc.bfox | Sample Bourne Again Shell init file (written by Fox). | |
| ./startup-files/README | README | |
| ./startup-files/apple | Example startup files for Mac OS X. | |
| ./startup-files/apple/aliases | Sample aliases for Mac OS X. | |
| ./startup-files/apple/bash.defaults | Sample User preferences file. | |
| ./startup-files/apple/environment | Sample Bourne Again Shell environment file. | |
| ./startup-files/apple/login | Sample login wrapper. | |
| ./startup-files/apple/logout | Sample logout wrapper. | |
| ./startup-files/apple/rc | Sample Bourne Again Shell config file. | |
| ./startup-files/apple/README | README |
Copyright © 1996-2009 by Dr. Nikolai Bezroukov. www.softpanorama.org was created as a service to the UN Sustainable Development Networking Programme (SDNP) in the author free time. Submit comments This document is an industrial compilation designed and created exclusively for educational use and is placed under the copyright of the Open Content License(OPL). Site uses AdSense so you need to be aware of Google privacy policy. Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.
Disclaimer:
Last modified: August 22, 2009