Bash Scripting: Difference between revisions

From Elvanör's Technical Wiki
Jump to navigation Jump to search
Line 80: Line 80:


the output is not the expected 35. This is because MYVAR expansion happens before echo is launched with the MYVAR variable set on the environment.
the output is not the expected 35. This is because MYVAR expansion happens before echo is launched with the MYVAR variable set on the environment.
== Parameters ==
* Parameters can be "moved" using the shift keyword, which can be very useful when parsing all parameters given to a script. Warning however: if you use shift 2 for instance and there is only one parameter, this will silently fail and not move anything at all.


= Arrays =
= Arrays =

Revision as of 22:00, 18 August 2009

General

Command Line arguments conventions

  • Long options are represented by two starting hyphens. Long options and short options should be provided before any other arguments.

Subshell

  • To launch a command in a subshell, use (). It's usually used with $(), since that allows a variable to capture stdout of the launched process. Note that using backticks is deprecated.

Standard Input / Output

  • "<<<" can be used to feed a string as standard input.

String Manipulations

  • To replace all substrings by another, use the following syntax:
echo ${stringZ//abc/xyz}

This would replace all occurences of abc in stringZ by xyz. The following replaces only the first match:

echo ${stringZ/abc/xyz}

To replace something at the end of a string, use:

echo ${stringZ/%abc/XYZ}

Heredocs

  • You can use << to start a heredoc. You must supply a limit string (EOF for instance). Note that you can still indent the heredoc; in this case use <<- which will strip the leading tabs of every line.
  • You can use expansion inside a heredoc (via $) and even expand inside an arithmetic context: $(( )).

Control structures

Loops

  • To easily loop over all the files in a directory, you can just use parameter expansion:
for file in *; do echo $file; done

Tests

  • The then keyword is mandatory after if / fi.
  • -n checks if a string is not empty, -z if it is empty.
  • [ is not a keyword but a command (a program!). It is recommended to use [[ in tests which is a keyword.
  • Note that [[ myVariable ]] will output true even if myVariable is equal to 0. The test must be explicit.
  • After [[ and ]] there must be a space character.

Strings

  • "==" can be used inside [[ to check for string equality.

Variables and parameters

Special Symbols

  • "$@" expands to all command-line parameters.
  • "\n" in a variable does not necessarily works as expected. Eg, no newline is created.
  • \ before a newline actually escapes the newline. Thus, you can create multi-line strings or commands just by terminating a line with the \ symbol.
  • Positional parameters can be accessed with $1, $2 etc. You only need brackets {} after the 9th parameter ("${10}").

Quoting

  • If you need to expand special characters such as *, you cannot quote.
  • Use single quotes rather than double quotes, especially in sed. If you use double quotes, the \ itself won't be taken as a \ for escaping, thus causing problems.
  • If you write \ and then a newline, the newline will be escaped which allows you to write multiline strings.

Expansion

  • The shell expands stuff like aaa* as soon as it sees this expression. Thus if you define a custom function myFunc(), and call it like that:
myFunc stuff*

If there are two files stuff1 and stuff2 in the current directory, $1 and $2 will be set to stuff1 and stuff2. Even if they are quoted ("$1", "$2") since the expansion took place before.

  • If you write a command like:
MYVAR="35" echo ${MYVAR}

the output is not the expected 35. This is because MYVAR expansion happens before echo is launched with the MYVAR variable set on the environment.

Parameters

  • Parameters can be "moved" using the shift keyword, which can be very useful when parsing all parameters given to a script. Warning however: if you use shift 2 for instance and there is only one parameter, this will silently fail and not move anything at all.

Arrays

  • The length of an array can be obtained via "${#array[@]}".

Arithmetic context

  • When within double parenthesis (( )) or after the let keyword, Bash enters arithmetic context. You don't need to quote variables or precede them with a $ sign. Tests also work as expected, eg more like in their C counterpart. For example,
if (( myVariable )) 

will return false if myVariable is equal to 0.

  • Arithmetic context also applies when in an array [].

Functions

  • Functions must be declared before they are called. You call a function without the () (eg., just the function name).

Command Line Utilities

  • sdiff -s will generate a formatted output of the differences between two files. Very useful.

sed

  • sed is a stream editor (help here). It is extremely powerful and can do almost everything under the sun. It can:
    • delete a line with command d;
    • append with command a;
    • use multiline strings if needed, with the standard Bash mechanism;
    • use several replacements on one line. In this case you need to add the option -e to all changes (else sed will only take one argument for replacement). Example:
sed -e "/dir=\"plugins\/org.eclipse.jdt.apt.pluggable.core\"/d" \
	-e "/dir=\"plugins\/org.eclipse.jdt.compiler.apt/d" \
	-e "/dir=\"plugins\/org.eclipse.jdt.compiler.tool\"/d" \

grep

  • grep is normally used on lines (via stdin), but it can also be used for files if given as arguments. If you use the -l switch, the normal output is disabled and it just prints the path to the files where output would have been printed.

find

  • Every option given to find is a predicate. For instance:
    • -type d: will only find directories
    • -exec bash: will load bash and consider the file if the bash invocation returned 0
  • Complex example, which will print out all subdirectories of /var/db/pkg/ that do NOT contain a file named CONTENTS:
find /var/db/pkg/ -type d -exec bash -c '! -e "$1/CONTENTS" ' -- {} \; -print
  • bash is invoked with 4 arguments, -c, then the command string, then -- as $0 and then {} (which corresponds to the canonical file path given by find) as $1.

chroot

  • A mandatory command should be given to chroot; it represents the command that will be executed inside the chroot environment. If you wish to chroot inside a Bash script, you should copy over a script to the new chroot and execute it.