<c>bash</c> -- Standard Shell

A thorough understanding of bash programming is vital when working with ebuilds.

Bash Conditionals Basic Selection

The basic conditional operator is the if statement:

if something ; then do_stuff fi
Multiple Selection

Multiple pronged selection can be done using else and elif:

if something ; then do_stuff elif something_else ; then do_other_stuff elif full_moon ; then howl else turn_into_a_newt fi You must specify at least one statement inside each block. The following will not work: if some_stuff ; then # A statement is required here. a blank or a comment # isn't enough! else einfo "Not some stuff" fi

If you really don't want to restructure the block, you can use a single colon (:) on its own as a null statement.

if some_stuff ; then # Do nothing : else einfo "Not some stuff" fi
Selection Tests

To do comparisons or file attribute tests, [ ] or [[ ]] blocks are needed.

# is $foo zero length? if [[ -z "${foo}" ]] ; then die "Please set foo" fi # is $foo equal to "moo"? if [[ "${foo}" == "moo" ]] ; then einfo "Hello Larry" fi # does "${ROOT}/etc/deleteme" exist? if [[ -f "${ROOT}/etc/deleteme" ]] ; then einfo "Please delete ${ROOT}/etc/readme manually!" fi
Single versus Double Brackets in <c>bash</c> The [[ ]] form is generally safer than [ ] and should be used in all new code.

This is because [[ ]] is a bash syntax construct, whereas [ ] is a program which happens to be implemented as an internal as such, cleaner syntax is possible with the former. For a simple illustration, consider:

bash$ [ -n $foo ] && [ -z $foo ] && echo "huh?" huh? bash$ [[ -n $foo ]] && [[ -z $foo ]] && echo "huh?" bash$
String Comparison in <c>bash</c>

The general form of a string comparison is string1 operator string2. The following are available:

== (also =) String equality != String inequality < String lexiographic comparison (before) > String lexiographic comparison (after) =~ String regular expression match (bash 3 only, not currently allowed in ebuilds)
Operator Purpose
String Tests in <c>bash</c>

The general form of string tests is -operator "string". The following are available:

-z "string" String has zero length -n "string" String has non-zero length
Operator Purpose
To check whether a variable is set and not blank, use -n "${BLAH}" rather than -n $BLAH. The latter will cause problems in some situations if the variable is unset.
Integer Comparison in <c>bash</c>

The general form of integer comparisons is int1 -operator int2. The following are available:

-eq Integer equality -ne Integer inequality -lt Integer less than -le Integer less than or equal to -gt Integer greater than -ge Integer greater than or equal to
Operator Purpose
File Tests in <c>bash</c>

The general form of a file test is -operator "filename". The following are available (lifted from man bash):

-a file Exists (use -e instead) -b file Exists and is a block special file -c file Exists and is a character special file -d file Exists and is a directory -e file Exists -f file Exists and is a regular file -g file Exists and is set-group-id -h file Exists and is a symbolic link -k file Exists and its sticky bit is set -p file Exists and is a named pipe (FIFO) -r file Exists and is readable -s file Exists and has a size greater than zero -t fd Descriptor fd is open and refers to a terminal -u file Exists and its set-user-id bit is set -w file Exists and is writable -x file Exists and is executable -O file Exists and is owned by the effective user id -G file Exists and is owned by the effective group id -L file Exists and is a symbolic link -S file Exists and is a socket -N file Exists and has been modified since it was last read
Operator Purpose
File Comparison in <c>bash</c>

The general form of a file comparison is "file1" -operator "file2". The following are available (lifted from man bash):

file1 -nt file2 file1 is newer (according to modification date) than file2, or if file1 exists and file2 does not. file1 -ot file2 file1 is older than file2, or if file2 exists and file1 does not. file1 -ef file2 file1 and file2 refer to the same device and inode numbers.
Operator Purpose
Boolean Algebra in <c>bash</c>

There are constructs available for boolean algebra ('and', 'or' and 'not'). These are used outside of the [[ ]] blocks. For operator precedence, use ( ).

first || second first or second (short circuit) first && second first and second (short circuit) ! condition not condition
Construct Effect
These will also sometimes work inside [[ ]] constructs, and using ! before a test is fairly common. [[ ! -f foo ]] && bar is fine. However, there are catches [[ -f foo && bar ]] will not work properly, since commands cannot be run inside [[ ]] blocks.

Inside [ ] blocks, several -test style boolean operators are available. These should be avoided in favour of [[ ]] and the above operators.

Bash Iterative Structures

There are a few simple iterative structures available from within bash. The most useful of these is a for loop. This can be used to perform the same task upon multiple items.

for myvar in "the first" "the second" "and the third" ; do einfo "This is ${myvar}" done

There is a second form of the for loop which can be used for repeating an event a given number of times.

for (( i = 1 ; i <= 10 ; i++ )) ; do einfo "i is ${i}" done

There is also a while loop, although this is usually not useful within ebuilds.

while hungry ; do eat_cookies done

This is most commonly used to iterate over lines in a file:

while read myline ; do einfo "It says ${myline}" done < some_file

See for an explanation of why while read < file should be used over cat file | while read.

Bash Variable Manipulation

There are a number of special ${} constructs in bash which either manipulate or return information based upon variables. These can be used instead of expensive (or illegal, if we're in global scope) external calls to sed and friends.

<c>bash</c> String Length

The ${#somevar} construct can be used to obtain the length of a string variable.

somevar="Hello World" echo "${somevar} is ${#somevar} characters long"
<c>bash</c> Variable Default Values

There are a number of ways of using a default value if a variable is unset or zero length. The ${var:-value} construct expands to the value of ${var} if it is set and not null, or value otherwise. The ${var-value} construct is similar, but checks only that the variable is set.

The ${var:=value} and ${var=value} forms will also assign value to var if var is unset (and also set, but null for the := form).

The ${var:?message} form will display message to stderr and then exit if var is unset or null. This should generally not be used within ebuilds as it does not use the die mechanism. There is a ${var?message} form too.

The ${var:+value} form expands to value if var is set and not null, or a blank string otherwise. There is a ${var+value} form.

<c>bash</c> Substring Extraction

The ${var:offset} and ${var:offset:length} constructs can be used to obtain a substring. Strings are zero-indexed. Both offset and length are arithmetic expressions.

The first form with a positive offset returns a substring starting with the character at offset and continuing to the end of a string. If the offset is negative, the offset is taken relative to the end of the string.

For reasons which will not be discussed here, any negative value must be an expression which results in a negative value, rather than simply a negative value. The best way to handle this is to use ${var:0-1}. ${var:-1} will not work.

The second form returns the first length characters of the value of ${var} starting at offset. If offset is negative, the offset is taken from the end of the string. The length parameter must not be less than zero. Again, negative offset values must be given as an expression.

<c>bash</c> Command Substitution

The $(command) construct can be used to run a command and capture the output (stdout) as a string.

The `command` construct also does this, but should be avoided in favour of $(command ) for clarity, ease of reading and nesting purposes. myconf="$(use_enable acl) $(use_enable nls) --with-tlib=ncurses"
<c>bash</c> String Replacements

There are three basic string replacement forms available: ${var#pattern}, ${var%pattern} and ${var/pattern/replacement}. The first two are used for deleting content from the start and end of a string respectively. The third is used to replace a match with different content.

The ${var#pattern} form will return var with the shortest match of pattern at the start of the value of var deleted. If no match can be made, the value of var is given. To delete the longest match at the start, use ${var##pattern} instead.

The ${var%pattern} and ${var%%pattern} forms are similar, but delete the shortest and longest matches at the end of var respectively.

The terms greedy and non-greedy are sometimes used here (% and # being the non-greedy forms). This is arguably incorrect, but the terms are fairly close.

The ${var/pattern/replacement} construct expands to the value of var with the first match of pattern replaced with replacement. To replace all matches, ${var//pattern/replacement} can be used.

man bash incorrectly describes what will be matched. Of all the possible leftmost matches, the longest will be taken. Yes, really, the longest, even if it involves favouring later groups or later branches. This is not like perl or sed. See IEEE1003.1-2004-9.1 for details.

To match only if pattern occurs at the start of the value of var, the pattern should begin with a # character. To match only at the end, the pattern should begin with a %.

If replacement is null, matches are deleted and the / following pattern may be omitted.

The pattern may contain a number of special metacharacters for pattern matching.

tables of bash metachars

If the extglob shell option is enabled, a number of additional constructs are available. These can be extremely useful sometimes.

table of extra bash goodies
<c>bash</c> Arithmetic Expansion

The $(( expression )) construct can be used for integer arithmetic evaluation. expression is a C-like arithmetic expression. The following operators are supported (the table is in order of precedence, highest first):

var++, var-- Variable post-increment, post-decrement ++var, --var Variable pre-increment, pre-decrement -, + Unary minus and plus !, ~ Logical negation, bitwise negation ** Exponentiation *, /, % Multiplication, division, remainder +, - Addition, subtraction <<, >> Left, right bitwise shifts <=, >=, <, > Comparison: less than or equal to, greater than or equal to, strictly less than, strictly greater than ==, != Equality, inequality & Bitwise AND ^ Bitwise exclusive OR | Bitwise OR && Logical AND || Logical OR expr ? expr : expr Conditional operator =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= Assignment expr1 , expr2 Multiple statements
Operators Effect
There is no **= assignment operator.