Bash (Unix shell)
GNU replacement for the Bourne shell
- 53 min read
- 13 chapters
Related on Lably
Through Operating system, Unix shell and Login
The Bash command syntax is a superset of the Bourne shell's syntax, from which all basic features of the Bash syntax were copied. As a result, Bash can execute the vast majority of Bourne shell scripts without modification. Some other ideas were borrowed from the C shell, its successor tcsh, and the Korn Shell. It is available on nearly all modern operating systems, making it a versatile tool in various computing environments.
Definitions
ASCII, strings and numbers
The input language to the shell shall be first recognized at the character level.
— IEEE & The Open Group
<span id="mwRw"></span><span class="gp" id="mwSA">$ </span><span class="nb" id="mwSQ">printf</span><span class="w" id="mwSg"> </span><span class="s1" id="mwSw">'<newline>: <%b>\n'</span><span class="w" id="mwTA"> </span><span class="s1" id="mwTQ">$'\n'</span> <span class="go" id="mwTg"><newline>: <</span> <span class="go" id="mwTw">></span> <span class="gp" id="mwUA">$ </span><span class="nb" id="mwUQ">printf</span><span class="w" id="mwUg"> </span><span class="s1" id="mwUw">'<tab>: <%b>\n'</span><span class="w" id="mwVA"> </span><span class="s1" id="mwVQ">$'\t'</span> <span class="go" id="mwVg"><tab>: < ></span> <span class="gp" id="mwVw">$ </span><span class="nb" id="mwWA">printf</span><span class="w" id="mwWQ"> </span><span class="s1" id="mwWg">'<space>: <%s>\n'</span><span class="w" id="mwWw"> </span><span class="s2" id="mwXA">" "</span> <span class="go" id="mwXQ"><space>: < ></span> <span class="gp" id="mwXg">$ </span><span class="nb" id="mwXw">printf</span><span class="w" id="mwYA"> </span><span class="s1" id="mwYQ">'<NUL>: <%b>\n'</span><span class="w" id="mwYg"> </span><span class="s1" id="mwYw">$'\0'</span> <span class="go" id="mwZA"><NUL>: <></span>
Any series of characters is called a "string", or sometimes a "string literal". In Unix-like operating systems, all characters, printable and non-printing, except for a few such as the null character and forward slash /, can be used in filenames. In addition, all strings are case-sensitive.
Bash, like many other programming languages, uses zero-based numbering.
Control+key combinations
The Control+key functionality is provided by GNU Readline and is available in interactive mode only. Certain keypress combinations allow a user to operate Bash to use tab completion and to search the command history.
- Tab ↹ – Activate tab completion
- ↑ – Scroll up (i.e. backward) in the command history
- ↓ – Scroll down (i.e. forward) in the command history
- Ctrl+r – Search the command history
Some keypress combinations also allow a user to operate the terminal emulator in order to move the cursor within the terminal window and to control the emulator program. By default, these keypress combinations in Bash mirror those of Emacs.
Default keybindings for control codes include:
- Ctrl+f – Move the cursor one character to the right
- Ctrl+b – Move the cursor one character to the left
- Alt+f – Move the cursor one word to the right
- Alt+b – Move the cursor one word to the left
- Ctrl+a – Move the cursor to the beginning of the current commandline
- Ctrl+c – Cancels the current command and presents a new prompt
- Ctrl+d – Closes the current Bash instance, possibly also closing the terminal-emulator
- Ctrl+e – Move the cursor to the end of the current commandline
- Ctrl+q – Wake the terminal; buffered keypresses are then processed
- Ctrl+s – Put the terminal to sleep
- Ctrl+w – Remove one word to the left of the cursor
- Ctrl+z – Stop a foregrounded process
Vi keybindings are also available and can be enabled by running set -o vi.
Syntax
When Bash reads a full command line, the complete string is broken down into tokens. "Tokens" are identified using, and separated from each other using metacharacters.
As of Bash 5.3, the 10 metacharacters are the space, tab, and newline, as well as the following characters: |&;()<>
"Blanks" are composed entirely of unquoted metacharacters, "operators" each contain at least one unquoted metacharacter and "words" may not include any unquoted metacharacters.
In practice, Bash breaks down full command strings into tokens or groups of tokens that do contain metacharacters and tokens or groups of tokens that do not contain any metacharacters—called "words". From there it further breaks words down into more specific, meaningful pieces like command names, variable assignment statements, etc.
The two blanks are space and tab.
Operators
Control operators perform a control function. They can be either a newline or one of the following: ||, &&, &, ;, ;;, ;&, ;;&, |, |&, (, or ).
Redirection operators redirect the input or output streams. They include <, >, &>, <<, and <<<.
Words
A word is a sequence of (non-meta-) characters treated as a single unit by the shell. A reserved word is a kind of a word that has a special meaning to the shell.
A name is a kind of a word separate from reserved words. Names (A) consist solely of letters, underscores and numbers, (B) begin with either a letter or an underscore, and (C) may not begin with a number. Also called identifiers, names may be used for naming variables and functions.
Sixteen of the twenty-two "reserved words", which may be characters or words are as follows:
<span id="mw-w"></span><span class="s1" id="mw_A">'!'</span><span class="w" id="mw_Q"> </span><span class="s1" id="mw_g">'[['</span><span class="w" id="mw_w"> </span><span class="s1" id="mwAQA">'{'</span><span class="w" id="mwAQE"> </span><span class="s1" id="mwAQI">']]'</span><span class="w" id="mwAQM"> </span><span class="s1" id="mwAQQ">'}'</span><span class="w" id="mwAQU"> </span><span class="k" id="mwAQY">case</span><span class="w" id="mwAQc"> </span><span class="k" id="mwAQg">in</span><span class="w" id="mwAQk"> </span><span class="k" id="mwAQo">esac</span><span class="w" id="mwAQs"> </span><span class="k" id="mwAQw">for</span><span class="w" id="mwAQ0"> </span><span class="k" id="mwAQ4">do</span><span class="w" id="mwAQ8"> </span><span class="k" id="mwARA">done</span><span class="w" id="mwARE"> </span><span class="k" id="mwARI">if</span><span class="w" id="mwARM"> </span><span class="k" id="mwARQ">then</span><span class="w" id="mwARU"> </span><span class="k" id="mwARY">elif</span><span class="w" id="mwARc"> </span><span class="k" id="mwARg">else</span><span class="w" id="mwARk"> </span><span class="k" id="mwARo">fi</span><span class="w" id="mwARs"> </span>...Names may only contain the characters ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.
In the following example of a full command string, metacharacters have a comma placed above them, ,, reserved words have a caret placed beneath them, ^, and other tokens have a backtick placed also beneath them, `.
<span id="mwASc"></span><span class="gp" id="mwASg">$ </span><span class="c1" id="mwASk">#, , , ,, , ,, ,</span> <span class="gp" id="mwASo">$ </span><span class="k" id="mwASs">if</span><span class="w" id="mwASw"> </span><span class="nb" id="mwAS0">echo</span><span class="w" id="mwAS4"> </span>foo<span class="p" id="mwAS8">;</span><span class="w" id="mwATA"> </span><span class="k" id="mwATE">then</span><span class="w" id="mwATI"> </span><span class="nv" id="mwATM">bar</span><span class="o" id="mwATQ">=</span>abc<span class="p" id="mwATU">;</span><span class="w" id="mwATY"> </span><span class="k" id="mwATc">fi</span> <span class="gp" id="mwATg">$ </span><span class="c1" id="mwATk"># ^^ ```` ``` ^^^^ ``````` ^^</span>
Subshells
A "subshell" is an additional instance of the shell which has been initialized by a current instance of the shell. When a "parent" shell creates a subshell, or a "child" shell, an exact copy of the parent's environment information is re-created and becomes the environment of the subshell.
In Bash, in non-arithmetic contexts, one can force the use of a subshell by enclosing a full command string in single parentheses.
<span id="mwAUA"></span><span class="gp" id="mwAUE">$ </span><span class="nb" id="mwAUI">echo</span><span class="w" id="mwAUM"> </span>foo<span class="p" id="mwAUQ">;</span><span class="w" id="mwAUU"> </span><span class="o" id="mwAUY">(</span><span class="w" id="mwAUc"> </span><span class="nb" id="mwAUg">echo</span><span class="w" id="mwAUk"> </span>foo<span class="w" id="mwAUo"> </span><span class="o" id="mwAUs">)</span> <span class="go" id="mwAUw">foo</span> <span class="go" id="mwAU0">foo</span>
For this simple case, the preceding two commands are equivalent, however, use of subshells can have certain unexpected side effects. There are numerous different forms of syntax which can cause the initialization of a subshell. A non-comprehensive list of operators that cause the initialization of a subshell is as follows:
- Subshells syntax,
(), for example, would initialize a subshell:<span id="mwAVQ"></span><span class="gp" id="mwAVU">$ </span><span class="o" id="mwAVY">(</span><span class="w" id="mwAVc"> </span>program<span class="w" id="mwAVg"> </span>arga<span class="w" id="mwAVk"> </span>argb<span class="w" id="mwAVo"> </span><span class="o" id="mwAVs">)</span>
- Piping syntax,
A | B, would initialize multiple subshells, one for each separate command in the pipeline:<span id="mwAWI"></span><span class="gp" id="mwAWM">$ </span>program1<span class="w" id="mwAWQ"> </span>abc<span class="w" id="mwAWU"> </span>def<span class="w" id="mwAWY"> </span><span class="p" id="mwAWc">|</span><span class="w" id="mwAWg"> </span>program2<span class="w" id="mwAWk"> </span>-abc
Expansion
Data structures
Bash offers variables and arrays as data structures, and though there are numerous kinds of each of these available, the data structures are relatively simple compared to other languages like C or Java. All data is stored in memory as a string.
Beginning a word with a dollar character signifies that the word is the name of a variable or array. Surrounding the dollar / variable name syntax in double quotes is always advised. This practice shields the value(s) held by the parameter(s) from unwanted side effects.
Wrapping the variable name in curly brackets (braces) {} is recommended for readability and consistency between variables and arrays. When writing variables, curly brackets are optional and square brackets would be a syntax error. The parameter names are always on the left side of the equals sign and values are always on the right.
Variables
A variable is assigned to using the syntax name=value.
To use a variable, the syntax $name is used, or ${name}, which expands to the value assigned to the variable.
The latter syntax must be used for certain names to prevent unwanted side effects. For example, $10 will be parsed as ${1}0, so using ${10} means it will be parsed as intended.
Positional parameters, usually passed to a bash script, are denoted by the variables numbered starting from $1. Special parameters are signified by punctuation characters. For example, "$@" expands to a list of the first through last positional parameters, individually requoted, separated by spaces.
Environment variables are signified by all capital letters. Environment variables include UNIX variables like LESS_SIGUSR1, and Bourne shell variables such as HOME. Scripting variables are signified by all lower case letters or CamelCase. This is only convention; any variable can be passed to the export command to be made into an environment variable.
Arrays
Arrays are data structures which hold multiple values.
Arrays have a set of square brackets placed at the end of the variable name and inside the curly braces. When writing arrays, curly braces and square brackets are required.
An array is assigned using the syntax name=( value1 value2 ... ). It is expanded using ${quux[@]} or ${quux[*]} or ${quux[1]}, depending on the use case.
Each kind of parameter is distinguished by a specific naming convention.
Since Bash 4.0, Bash also supports associative arrays.
In this article, examples of variables from this section include ${foo}, PID, PWD, EUID, $$, ${quux} and ${zork} .
Execution
"Execution" of a given program occurs when a user (or some other program) asks the operating system to act upon the instructions contained in the given program.
By default, Bash reads user code one line at a time, interprets any newline or semi-colon character ; as the end of the current command, and executes commands in sequence. If an interactive command extends beyond the width of the terminal emulator, it is usually possible to keep typing and the command will wrap around. To extend a command beyond a newline onto an additional line, it is necessary that the final character of the first line be an unescaped backslash, \, which signals "line continuation". Bash always finishes parsing and executing one full commandline before moving on to and beginning with the parsing of the next commandline.
<span id="mwAcg"></span><span class="gp" id="mwAck">$ </span><span class="nv" id="mwAco">foo</span><span class="o" id="mwAcs">=</span>aa<span class="w" id="mwAcw"> </span><span class="nv" id="mwAc0">bar</span><span class="o" id="mwAc4">=</span>bb<span class="w" id="mwAc8"> </span><span class="nv" id="mwAdA">quux</span><span class="o" id="mwAdE">=</span>cc<span class="w" id="mwAdI"> </span><span class="nv" id="mwAdM">zork</span><span class="o" id="mwAdQ">=</span>dd<span class="p" id="mwAdU">;</span><span class="w" id="mwAdY"> </span><span class="nb" id="mwAdc">set</span><span class="w" id="mwAdg"> </span>-o<span class="w" id="mwAdk"> </span>xtrace <span class="gp" id="mwAdo">$ </span>:<span class="w" id="mwAds"> </span><span class="s2" id="mwAdw">"</span><span class="si" id="mwAd0">${</span><span class="nv" id="mwAd4">foo</span><span class="si" id="mwAd8">}</span><span class="s2" id="mwAeA">"</span><span class="p" id="mwAeE">;</span><span class="w" id="mwAeI"> </span>:<span class="w" id="mwAeM"> </span><span class="s2" id="mwAeQ">"</span><span class="si" id="mwAeU">${</span><span class="nv" id="mwAeY">bar</span><span class="si" id="mwAec">}</span><span class="s2" id="mwAeg">"</span> <span class="go" id="mwAek">+ : aa</span> <span class="go" id="mwAeo">+ : bb</span> <span class="gp" id="mwAes">$ </span>:<span class="w" id="mwAew"> </span><span class="s2" id="mwAe0">"</span><span class="si" id="mwAe4">${</span><span class="nv" id="mwAe8">quux</span><span class="si" id="mwAfA">}</span><span class="s2" id="mwAfE">"</span><span class="w" id="mwAfI"> </span><span class="se" id="mwAfM">\</span> <span class="gp" id="mwAfQ">> </span>:<span class="w" id="mwAfU"> </span><span class="s2" id="mwAfY">"</span><span class="si" id="mwAfc">${</span><span class="nv" id="mwAfg">zork</span><span class="si" id="mwAfk">}</span><span class="s2" id="mwAfo">"</span> <span class="go" id="mwAfs">+ : cc : dd</span>The first word of a command line is known as the "command position". Under UNIX coventionality, the first word of the command line is always some kind of command, and the rest of the words in the command line string are either options for the command, arguments for the options, or some kind of input upon which the command will operate. "Options" are also called "flags", "switches", or, more formally, "operators". When Bash attempts to locate a command for execution, the directories it searches are those listed in the $PATH variable and the current working directory.
<span id="mwAgQ"></span><span class="gp" id="mwAgU">$ </span><span class="c1" id="mwAgY"># [COMMAND POSITION] [OPTION] [ARGUMENTS] </span> <span class="gp" id="mwAgc">$ </span><span class="c1" id="mwAgg"># ,--^ ,------------^ ,----^</span> <span class="gp" id="mwAgk">$ </span><span class="nb" id="mwAgo">declare</span><span class="w" id="mwAgs"> </span>-p<span class="w" id="mwAgw"> </span>USER<span class="w" id="mwAg0"> </span>BASH_VERSION <span class="go" id="mwAg4">declare -x USER="liveuser"</span> <span class="go" id="mwAg8">declare -- BASH_VERSION="5.2.37(1)-release"</span>
Users and PS1
A user account can be created for either a human or a programmatic user. In Unix-like operating systems, there are two kinds of users: "privileged" and "regular". A privileged user, such as root or the operating system kernel, is allowed to do anything whatsoever on the machine. Unprivileged users are limited in various ways.
When an interactive shell session waits for user input, by default it prints a particular string of characters to the screen. In Bash, the value of this waiting-string is held in the shell variable $PS1. For regular users, a common default value for $PS1 is the dollar character ($). For the superuser, a common default value is hash (#)
<span id="mwAiA"></span><span class="gp" id="mwAiE">$ </span>sudo<span class="w" id="mwAiI"> </span>--login<span class="w" id="mwAiM"> </span>--user<span class="w" id="mwAiQ"> </span>root <span class="go" id="mwAiU">[sudo] password for liveuser:</span> <span class="gp" id="mwAiY"># </span><span class="nb" id="mwAic">umask</span><span class="w" id="mwAig"> </span><span class="m" id="mwAik">077</span> <span class="gp" id="mwAio"># </span><span class="nb" id="mwAis">echo</span><span class="w" id="mwAiw"> </span>bob<span class="w" id="mwAi0"> </span>><span class="w" id="mwAi4"> </span>/home/liveuser/names.txt <span class="gp" id="mwAi8"># </span><span class="nb" id="mwAjA">exit</span> <span class="gp" id="mwAjE">$ </span>grep<span class="w" id="mwAjI"> </span>-e<span class="w" id="mwAjM"> </span>bob<span class="w" id="mwAjQ"> </span>./names.txt <span class="go" id="mwAjU">grep: ./names.txt: Permission denied</span>
Sign in to keep reading
12 more chapters are free with a Lably account.
Modes
Programming paradigm
Although most users think of the shell as an interactive command interpreter, it is really a programming language in which each statement runs a command. Because it must satisfy both the interactive and programming aspects of command execution, it is a strange language, shaped as much by history as by design.
Bash is written in C. A modular style can be approximated through good style and careful design. It is often used in an imperative or procedural style.
Interactive and non-interactive modes
As a command processor, Bash can operate in two modes: interactive or non-interactive. In interactive mode, commands are usually read from a terminal emulator. In non-interactive mode, which facilitates automation, commands are usually read from named files known today as shell scripts. When executed as a standalone command at the command-line interface (CLI), by default Bash opens a new shell in interactive mode.
Scripts
Shell scripts are text files that contain code, often commands, intended to be read and acted upon by some particular interpreter in a batch process in a non-interactive mode and without any further user interaction. Interpreted scripts are programs that do not require their source code to be compiled: all of the relevant source code is contained within the script. There are many programs which can serve as a script interpreter: Perl, AWK, etc. Interpreted scripts are most often written for Unix shells.
The first two characters of the first line of any (executable) shell script begins with a something called a shebang: literally the characters hash (#) and bang (!) side by side.
<span id="mwAmA"></span><span class="gp" id="mwAmE">$ </span>cat<span class="w" id="mwAmI"> </span>./example.sh <span class="gp" id="mwAmM">#</span>!<span class="w" id="mwAmQ"> </span>/bin/env<span class="w" id="mwAmU"> </span>bash <span class="go" id="mwAmY">echo foo</span>
If a script is intended to be run by a user as a stand-alone program on the commandline, then it is referred to as an "executable". By convention, the filenames of executable unix shell scripts are identified the suffix .sh. The "execute" bit can be enabled on a shell script with the utility chmod:
<span id="mwAm4"></span><span class="gp" id="mwAm8">$ </span>ls<span class="w" id="mwAnA"> </span>-l<span class="w" id="mwAnE"> </span>./example.sh <span class="go" id="mwAnI">-rw-r--r--.1 liveuser liveuser 32 Aug 3 22:33 example.sh</span> <span class="gp" id="mwAnM">$ </span>./example.sh <span class="go" id="mwAnQ">bash: ./example.sh: Permission denied</span> <span class="gp" id="mwAnU">$ </span>chmod<span class="w" id="mwAnY"> </span><span class="m" id="mwAnc">0744</span><span class="w" id="mwAng"> </span>./example.sh <span class="gp" id="mwAnk">$ </span>ls<span class="w" id="mwAno"> </span>-l<span class="w" id="mwAns"> </span>./example.sh <span class="go" id="mwAnw">-rwxr--r--.1 liveuser liveuser 32 Aug 3 22:33 example.sh</span> <span class="gp" id="mwAn0">$ </span>./example.sh <span class="go" id="mwAn4">foo</span>
The source builtin
With the source, or synonymous . command, Bash reads and executes shell commands from any text file by name.
Login and non-login shells
Bash can be executed as a login shell, or "session leader," in both interactive and non-interactive modes via the --login option. "Logging in" requires user authentication. For this reason, only one login shell exists per user session. In GNU/Linux, a user's login shell is identified in the /etc/passwd file.
<span id="mwApI"></span><span class="gp" id="mwApM">$ </span>awk<span class="w" id="mwApQ"> </span>-F<span class="w" id="mwApU"> </span><span class="s1" id="mwApY">':'</span><span class="w" id="mwApc"> </span><span class="s1" id="mwApg">'$1 ~ /root/'</span><span class="w" id="mwApk"> </span>/etc/passwd <span class="go" id="mwApo">root:x:0:0:Super User:/root:/bin/bash</span>
When a human user initiates a login session, this procedure often occurs in a graphical user interface (GUI). When a user opens a terminal emulator, the emulator executes a non-login instance of the user's login shell.
Logging out of a shell session from within a terminal emulator can be accomplished with the exit command or, by default in Bash, pressing Ctrl+d.
Startup source files
When Bash starts, it uses source to execute commands in a variety of dotfiles (see lists below). These dotfiles, unlike shell scripts, typically have neither the execute permission enabled nor a hash-bang. By default Bash will source a somewhat different set of files, and in a different sequence, depending on:
- How Bash is called: interactively, non-interactively, invoked with name
sh - Which options are used:
--login,--rcfile,--norc,--posix - Which environment variables are defined:
BASH_ENV,ENV, and - Which files exist:
/etc/profile~/.bash_profile~/.bash_login~/.profile~/.bash_logout, and~/.bashrcamong others.
Of course, any startup file can also execute commands from any other file. Startup files can affect shell behavior, terminal emulators, the X window system and the window manager.
POSIX mode
The POSIX IEEE 1003.1 standard specifies a common set of definitions that any shell system application (bash, dash, zsh, etc.) may conform to. Any shell user script (./myscript.sh) written in conformance with POSIX guidelines should be executable by any shell system application that has implemented the POSIX specification. As a result, there can be a reasonable expectation that POSIX-compliant scripts can be executed with success on any Unix or Unix-like operating systems which implements the POSIX standard (Linux, OpenBSD, Oracle Linux, HP-UX, etc.). These scripts are considered "portable" as they are and without any further modifications. The portion of POSIX that applies to shells and command line utilities is a subset of a larger group of POSIX standards that further specify how terminals and terminal emulators aught to function in order to also be considered portable.
When Bash is operating in POSIX mode, fewer features are available but the resulting code can be executed on a greater variety of operating systems.
To enable POSIX mode at the initialization of an interactive shell, Bash can be executed as either sh, bash --posix or bash -o posix.
To cause a script to be initialized in POSIX mode, one would use the either the hashbang #!/usr/bin/env sh or the less portable #!/bin/sh. When an instance of Bash is operating in POSIX mode, the environment variable $POSIXLY_CORRECT is defined, and the value of the environment variable SHELLOPTS includes the string posix.
<span id="mwAvM"></span><span class="gp" id="mwAvQ">$ </span><span class="nb" id="mwAvU">declare</span><span class="w" id="mwAvY"> </span>-p<span class="w" id="mwAvc"> </span>POSIXLY_CORRECT<span class="w" id="mwAvg"> </span>SHLVL <span class="go" id="mwAvk">bash: declare: POSIXLY_CORRECT: not found</span> <span class="go" id="mwAvo">declare -x SHLVL="1"</span> <span class="gp" id="mwAvs">$ </span>bash<span class="w" id="mwAvw"> </span>-o<span class="w" id="mwAv0"> </span>posix <span class="gp" id="mwAv4">$ </span><span class="nb" id="mwAv8">declare</span><span class="w" id="mwAwA"> </span>-p<span class="w" id="mwAwE"> </span>POSIXLY_CORRECT<span class="w" id="mwAwI"> </span>SHLVL <span class="go" id="mwAwM">declare -- POSIXLY_CORRECT="y"</span> <span class="go" id="mwAwQ">declare -x SHLVL="2"</span>
The full list of features available in Bash which are not specified by POSIX is considerable. Here is a partial list:
- Any arrays other than the array of positional parameters,
$@, are not POSIX - The double bracket extended test construct,
[[...]], is not POSIX[...]andtestare POSIX
- One of the double-parentheses arithmetic-evaluation syntaxes,
((...)), is not POSIX$((...))is POSIX
- Brace expansion,
kernel{,-headers}, is not POSIX - Dynamic scoping of parameters and the
localbuiltin are not POSIX - Process substitution,
<(...), is not POSIX - Certain string-manipulation operations in parameter expansions are not POSIX
- Most Bash builtin commands are not POSIX
- The command
enable -sprints the list of Bourne special builtins, which are POSIX<span id="mwAyc"></span><span class="gp" id="mwAyg">$ </span><span class="nb" id="mwAyk">enable</span><span class="w" id="mwAyo"> </span>-s<span class="w" id="mwAys"> </span><span class="p" id="mwAyw">|</span><span class="w" id="mwAy0"> </span>wc<span class="w" id="mwAy4"> </span>--lines <span class="go" id="mwAy8">16</span> <span class="gp" id="mwAzA">$ </span><span class="nb" id="mwAzE">enable</span><span class="w" id="mwAzI"> </span><span class="p" id="mwAzM">|</span><span class="w" id="mwAzQ"> </span>wc<span class="w" id="mwAzU"> </span>--lines <span class="go" id="mwAzY">61</span>
- The
enablebuiltin itself is not POSIX - In Bash, in non-POSIX mode, the
.andsourcebuiltins are synonymous- The
.(i.e., 'dot') builtin is POSIX, however - The
sourcebuiltin is not POSIX
- The
- The command
- The
$EPOCHSECONDSand$EPOCHREALTIMEshell variables are not POSIX
System commands which are available in modern Unix-like operating systems, and which are also specified by POSIX, may have fewer option flags or fewer relevant environment variables available under POSIX. Most (such as ls) are standalone programs in the /bin, /usr/bin, /sbin or /usr/sbin directories (in Linux, typically provided by GNU coreutils or BusyBox) rather than Bash builtins.
Because of these and other differences, modern (version 5) Bash shell scripts are rarely runnable "as-is" under the Bourne or legacy Korn shell interpreters. Scripting with portability in mind is becoming less common as GNU/Linux becomes more widespread.
Code that is valid syntax in Bash but not specified by POSIX is called a "bashism". The program checkbashisms can be used to make sure that a script can be executed in Debian Linux without any portability errors. Vidar Holen's shellcheck is another static linter written in Haskell which can parse script syntax for compatibility with any or all of bash, dash, ksh, and Bourne sh.
The syntax requirements for each shell are each a little different. For example, Debian's policy allows some extensions in their scripts (as they are in the dash shell), while a script intending to support pre-POSIX Bourne shells, like autoconf's configure, are even more limited in the features they can use.
Other modes
Restricted mode
A restricted shell is used to set up an environment more controlled than the standard shell. A restricted shell behaves identically to bash with the exception that numerous actions are disallowed or not performed, including:
- Changing directories with the
cdbuiltin. - Setting or unsetting the values of the
SHELL,PATH,HISTFILE,ENV, orBASH_ENVvariables. - Specifying command names containing slashes on the CLI.
- Using absolute pathnames as arguments to the
.,history, orhash -pcommands. - Specifying a path search with
. -porcommand -p. - Importing function definitions and parsing the value of
SHELLOPTSfrom the shell environment at startup. - Redirecting output using the
>,>,<>,>&,&>, and>>redirection operators. - Using the
execbuiltin to replace the shell with another command. - Altering shell builtins.
Once restricted mode is enabled, it cannot be disabled. These restrictions are enforced after any startup files are read, and it does not apply to shell scripts. Restricted mode is rarely used.
Privileged mode
In Bash, "privileged mode" is a rarely used option inherited from the SVR4.2 UNIX System V shell (circa 1992). It can be enabled with set -p and disabled with set +p.
When privileged mode is enabled, the SHELLOPTS shell variables includes the string "privileged".
Extended debugging mode
Enabled via bash --debugger at invocation or via shopt -s extdebug during either interactive or non-interactive modes. It uses a separate program called bashdb. extdebug is not available in POSIX mode. See documentation for more information. See also § Debugging.
Compatibility modes
Bash-4.0 introduced the concept of a shell compatibility level, specified as a set of options to the shopt builtin (compat31, compat32, compat40, compat41, and so on). There is only one current compatibility level – each option is mutually exclusive. The compatibility level is intended to allow users to select behavior from previous versions that is incompatible with newer versions while they migrate scripts to use current features and behavior. It's intended to be a temporary solution.
— The GNU Bash Reference Manual
Observability
The xtrace option
When xtrace is enabled, simple debugging content is printed to the terminal. It can be enabled with set -o xtrace or set -x, and disabled with set +o xtrace, set +x or set -. These options are also accepted at the commandline and at hash-bangs: #!/bin/bash -x, etc.
<span id="mwA8o"></span><span class="gp" id="mwA8s">$ </span>bash<span class="w" id="mwA8w"> </span>-x <span class="gp" id="mwA80">$ </span><span class="nb" id="mwA84">echo</span><span class="w" id="mwA88"> </span><span class="k" id="mwA9A">$((</span><span class="w" id="mwA9E"> </span><span class="m" id="mwA9I">2</span><span class="w" id="mwA9M"> </span><span class="o" id="mwA9Q">+</span><span class="w" id="mwA9U"> </span><span class="m" id="mwA9Y">2</span><span class="w" id="mwA9c"> </span><span class="k" id="mwA9g">))</span> <span class="go" id="mwA9k">+ echo 4</span> <span class="go" id="mwA9o">4</span> <span class="gp" id="mwA9s">$ </span><span class="nb" id="mwA9w">set</span><span class="w" id="mwA90"> </span>--<span class="w" id="mwA94"> </span><span class="m" id="mwA98">1</span><span class="w" id="mwA-A"> </span><span class="m" id="mwA-E">2</span><span class="w" id="mwA-I"> </span><span class="m" id="mwA-M">3</span> <span class="go" id="mwA-Q">+ set -- 1 2 3</span> <span class="gp" id="mwA-U">$ </span><span class="nb" id="mwA-Y">printf</span><span class="w" id="mwA-c"> </span><span class="s1" id="mwA-g">'<%s>\n'</span><span class="w" id="mwA-k"> </span><span class="s2" id="mwA-o">"</span><span class="nv" id="mwA-s">$@</span><span class="s2" id="mwA-w">"</span> <span class="go" id="mwA-0">+ printf '<%s>\n' 1 2 3</span> <span class="go" id="mwA-4"><1></span> <span class="go" id="mwA-8"><2></span> <span class="go" id="mwA_A"><3></span>
The xtrace shell setting is specified by POSIX. See also § Debugging.
The verbose option
The verbose option prints strings to the terminal as they are read, and before any expansions are performed. Rarely used.
Comments
Comments can be a valuable way of clarifying information or explaining a script or source file to someone else who might not be familiar with the scripter's intentions or context.
Standard comments in Bash are denoted with a hash character: #. Any text to the right of the hash to the end of the line will be ignored. Inline comments are allowed, but hash comments will not print during debugging. See also: § xtrace.
Comments denoted with a colon character, :, originated with the Thompson shell. Any arguments to the right of colon : builtin are ignored. Inline comments are not possible, but colon comments will print during debugging and any parameters will have been expanded.
<span id="mwBAw"></span><span class="gp" id="mwBA0">$ </span><span class="c1" id="mwBA4"># Define foo</span> <span class="gp" id="mwBA8">$ </span><span class="nv" id="mwBBA">foo</span><span class="o" id="mwBBE">=</span>bar<span class="w" id="mwBBI"> </span><span class="c1" id="mwBBM"># An inline hash comment occurs on the same line as a command</span> <span class="gp" id="mwBBQ">$ </span><span class="nb" id="mwBBU">set</span><span class="w" id="mwBBY"> </span>-x <span class="gp" id="mwBBc">$ </span><span class="c1" id="mwBBg"># A regular comment (no output)</span> <span class="gp" id="mwBBk">$ </span>:<span class="w" id="mwBBo"> </span><span class="s2" id="mwBBs">"</span><span class="si" id="mwBBw">${</span><span class="nv" id="mwBB0">foo</span><span class="si" id="mwBB4">}</span><span class="s2" id="mwBB8">"</span> <span class="go" id="mwBCA">+ : bar</span>Exit codes
When bash executes commands, exit status codes, also called "return codes," are produced which can offer some insight into the manner in which a program ceased running. The value of the most recently captured exit code is held within the shell parameter, 'question mark:' $?. In non-arithmetic contexts, (i.e., most of the time) the numerical or "Boolean" value of "true" is zero (0), and the value of "false" is one (1).
When a system command has executed, the intended meaning of its exit status can most often be found in its man page; usually a zero indicates success and a nonzero exit status indicates some kind of failure condition or partial success. ping is a well known command with three meaningful exit codes: 0, 1, and 2.
In Bash, within arithmetic contexts, the numerical truth values are reversed: "true" is one and "false" is zero. An arithmetic context can usually be identified by the syntax ((...)) or $((...)). If an arithmetic statement evaluates to the integer zero, then the statement is considered "true," and the exit code is one. If the statement evaluates to any number other than zero the arithmetic statement is "false" and the exit code is zero.
Not all Linux/UNIX commands provide meaningful exit codes beyond zero and one, and there is no standard system for definitions of exit codes in Linux.
<span id="mwBC8"></span><span class="gp" id="mwBDA">$ </span>true<span class="p" id="mwBDE">;</span><span class="w" id="mwBDI"> </span><span class="nb" id="mwBDM">echo</span><span class="w" id="mwBDQ"> </span><span class="nv" id="mwBDU">$?</span><span class="w" id="mwBDY"> </span><span class="c1" id="mwBDc"># Exit code means "true"</span> <span class="go" id="mwBDg">0</span> <span class="gp" id="mwBDk">$ </span>false<span class="p" id="mwBDo">;</span><span class="w" id="mwBDs"> </span><span class="nb" id="mwBDw">echo</span><span class="w" id="mwBD0"> </span><span class="nv" id="mwBD4">$?</span><span class="p" id="mwBD8">;</span><span class="w" id="mwBEA"> </span><span class="nb" id="mwBEE">echo</span><span class="w" id="mwBEI"> </span><span class="c1" id="mwBEM"># Exit code means "false"</span> <span class="go" id="mwBEQ">1</span> <span class="gp" id="mwBEU">$</span> <span class="gp" id="mwBEY">$ </span>bash<span class="w" id="mwBEc"> </span>-c<span class="w" id="mwBEg"> </span><span class="s1" id="mwBEk">'exit 99'</span><span class="p" id="mwBEo">;</span><span class="w" id="mwBEs"> </span><span class="nb" id="mwBEw">printf</span><span class="w" id="mwBE0"> </span><span class="s1" id="mwBE4">'exit-code: %d\n'</span><span class="w" id="mwBE8"> </span><span class="nv" id="mwBFA">$?</span> <span class="go" id="mwBFE">exit-code: 99</span> <span class="gp" id="mwBFI">$ </span><span class="o" id="mwBFM">((</span><span class="w" id="mwBFQ"> </span><span class="m" id="mwBFU">1</span><span class="w" id="mwBFY"> </span>-<span class="w" id="mwBFc"> </span><span class="m" id="mwBFg">1</span><span class="w" id="mwBFk"> </span><span class="o" id="mwBFo">))</span><span class="p" id="mwBFs">;</span><span class="w" id="mwBFw"> </span><span class="nb" id="mwBF0">printf</span><span class="w" id="mwBF4"> </span><span class="s1" id="mwBF8">'%d\n'</span><span class="w" id="mwBGA"> </span><span class="nv" id="mwBGE">$?</span><span class="w" id="mwBGI"> </span><span class="c1" id="mwBGM"># This exit code means "true"</span> <span class="go" id="mwBGQ">1</span> <span class="gp" id="mwBGU">$ </span><span class="o" id="mwBGY">((</span><span class="w" id="mwBGc"> </span><span class="m" id="mwBGg">1</span><span class="w" id="mwBGk"> </span>+<span class="w" id="mwBGo"> </span><span class="m" id="mwBGs">1</span><span class="w" id="mwBGw"> </span><span class="o" id="mwBG0">))</span><span class="p" id="mwBG4">;</span><span class="w" id="mwBG8"> </span><span class="nb" id="mwBHA">printf</span><span class="w" id="mwBHE"> </span><span class="s1" id="mwBHI">'%d\n'</span><span class="w" id="mwBHM"> </span><span class="nv" id="mwBHQ">$?</span><span class="w" id="mwBHU"> </span><span class="c1" id="mwBHY"># ...and this exit code means "false"</span> <span class="go" id="mwBHc">0</span>
Job control
The Bash shell has two modes of execution for commands: batch (asynchronous), and concurrent (synchronous). To execute commands in batch mode (i.e., in sequence) they must be separated by the character ;, or on separate lines:
<span id="mwBH8"></span><span class="gp" id="mwBIA">$ </span>command1<span class="p" id="mwBIE">;</span><span class="w" id="mwBII"> </span>command2 <span class="gp" id="mwBIM">$ </span>command3
In this example, when command1 is finished, command2 is executed, and when command2 has completed, command3 will execute. A background execution of command1 can occur using symbol & at the end of an execution command, and process will be executed in background while immediately returning control to the shell and allowing continued execution of commands.
<span id="mwBJM"></span><span class="gp" id="mwBJQ">$ </span>command1<span class="w" id="mwBJU"> </span><span class="p" id="mwBJY">&</span>
Or to have a concurrent execution of command1 and command2, they must be executed in the Bash shell in the following way:
<span id="mwBJ4"></span><span class="gp" id="mwBJ8">$ </span>command1<span class="w" id="mwBKA"> </span><span class="p" id="mwBKE">&</span><span class="w" id="mwBKI"> </span>command2
In this case command1 is executed in the background, & symbol, returning immediate control to the shell that executes command2 in the foreground. A process can be stopped and control returned to bash by typing Ctrl+z while the process is running in the foreground. A list of all processes, both in the background and stopped, can be achieved by running jobs:
<span id="mwBLI"></span><span class="gp" id="mwBLM">$ </span><span class="nb" id="mwBLQ">jobs</span> <span class="go" id="mwBLU">[1]- Running command1 &</span>
In the output, the number in brackets refers to the job id. The plus sign signifies the default process for bg and fg. The text "Running" and "Stopped" refer to the process state. The last string is the command that started the process.
The state of a process can be changed using various commands. The fg command brings a process to the foreground, while bg sets a stopped process running in the background. bg and fg can take a job id as their first argument, to specify the process to act on. Without one, they use the default process, identified by a plus sign in the output of jobs. The kill command can be used to end a process prematurely, by sending it a signal. The job id must be specified after a percent sign:
<span id="mwBMQ"></span><span class="gp" id="mwBMU">$ </span>sleep<span class="w" id="mwBMY"> </span><span class="m" id="mwBMc">100</span><span class="w" id="mwBMg"> </span><span class="p" id="mwBMk">&</span> <span class="go" id="mwBMo">[1] 4904</span> <span class="gp" id="mwBMs">$ </span><span class="nb" id="mwBMw">kill</span><span class="w" id="mwBM0"> </span>%1 <span class="gp" id="mwBM4">$ </span><span class="nb" id="mwBM8">jobs</span> <span class="go" id="mwBNA">[1]+ Terminated sleep 100</span>
Job control, also known as "Monitor mode," is enabled by default in interactive shells, and can be disabled with set +m.
Signals
Signaling is a means of inter-process communication (IPC). Sometimes a commandline process may seem to freeze in the middle of execution. In these instances it may become necessary to identify which process may be blocked and to manually end the offending process.
At an interactive terminal, it is usually sufficient to press Ctrl+c to end the current foreground process and return control back to the user prompt, or to press Ctrl+z to suspend it. Occasionally attempting to suspend a process will succeed when attempts to cancel a process appear unresponsive. In other cases it may be necessary to use the kill program to send an IPC signal. In this example, we use the kill command from a second terminal screen to terminate the process with PID 4331.
<span id="mwBOQ"></span><span class="gp" id="mwBOU">$ </span>tty<span class="w" id="mwBOY"> </span><span class="c1" id="mwBOc"># Terminal one</span> <span class="go" id="mwBOg">/dev/pts/0</span> <span class="gp" id="mwBOk">$ </span>whoami <span class="go" id="mwBOo">liveuser</span> <span class="gp" id="mwBOs">$ </span>sleep<span class="w" id="mwBOw"> </span><span class="m" id="mwBO0">1000</span><span class="w" id="mwBO4"> </span><span class="c1" id="mwBO8"># Command hangs</span>
<span id="mwBPI"></span><span class="gp" id="mwBPM">$ </span>tty<span class="w" id="mwBPQ"> </span><span class="c1" id="mwBPU"># Terminal two</span> <span class="go" id="mwBPY">/dev/pts/1</span> <span class="gp" id="mwBPc">$ </span>whoami <span class="go" id="mwBPg">liveuser</span> <span class="gp" id="mwBPk">$ </span>ps<span class="w" id="mwBPo"> </span>aux<span class="w" id="mwBPs"> </span><span class="p" id="mwBPw">|</span><span class="w" id="mwBP0"> </span>grep<span class="w" id="mwBP4"> </span>-e<span class="w" id="mwBP8"> </span>sleep<span class="w" id="mwBQA"> </span>-e<span class="w" id="mwBQE"> </span>PID <span class="go" id="mwBQI">USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND </span> <span class="go" id="mwBQM">liveuser 4331 0.0 0.0 230336 2312 pts/1 S+ 11:19 0:00 sleep 1000</span> <span class="go" id="mwBQQ">liveuser 4333 0.0 0.0 231248 2516 pts/0 S+ 11:19 0:00 grep --color=auto -e sleep -e PID</span> <span class="gp" id="mwBQU">$ </span><span class="nb" id="mwBQY">kill</span><span class="w" id="mwBQc"> </span><span class="m" id="mwBQg">4331</span> <span class="gp" id="mwBQk">$ </span>ps<span class="w" id="mwBQo"> </span>aux<span class="w" id="mwBQs"> </span><span class="p" id="mwBQw">|</span><span class="w" id="mwBQ0"> </span>grep<span class="w" id="mwBQ4"> </span>-e<span class="w" id="mwBQ8"> </span>sleep<span class="w" id="mwBRA"> </span>-e<span class="w" id="mwBRE"> </span>PID<span class="w" id="mwBRI"> </span><span class="c1" id="mwBRM"># The sleep process has ended</span> <span class="go" id="mwBRQ">USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND </span> <span class="go" id="mwBRU">liveuser 4333 0.0 0.0 231248 2516 pts/0 S+ 11:19 0:00 grep --color=auto -e sleep -e PID</span>
<span id="mwBRg"></span><span class="gp" id="mwBRk">$ </span>tty<span class="w" id="mwBRo"> </span><span class="c1" id="mwBRs"># Terminal one again</span> <span class="go" id="mwBRw">/dev/pts/0</span> <span class="gp" id="mwBR0">$ </span>whoami <span class="go" id="mwBR4">liveuser</span> <span class="gp" id="mwBR8">$ </span>sleep<span class="w" id="mwBSA"> </span><span class="m" id="mwBSE">1000</span> <span class="go" id="mwBSI">Terminated</span>
In Unix-like operating systems, a user is allowed to instruct the kernel to send a signal to a process that is owned by the user. A regular user may not send a signal to a privileged process. Signals can be sent to a process using the kill builtin or using the system binary of the same name.
<span id="mwBSg"></span><span class="gp" id="mwBSk">$ </span>whoami <span class="go" id="mwBSo">liveuser</span> <span class="gp" id="mwBSs">$ </span>ps<span class="w" id="mwBSw"> </span>aux<span class="w" id="mwBS0"> </span><span class="p" id="mwBS4">|</span><span class="w" id="mwBS8"> </span>awk<span class="w" id="mwBTA"> </span><span class="s1" id="mwBTE">'$2 == "1"'</span><span class="w" id="mwBTI"> </span><span class="c1" id="mwBTM"># Let\s view some info on the kernel process, process 1.</span> <span class="go" id="mwBTQ">root 1 0.0 0.2 37140 20440 ? Ss 04:44 0:18 /usr/lib/systemd/systemd --switched-root --system --deserialize=53 rhgb</span> <span class="gp" id="mwBTU">$ </span><span class="nb" id="mwBTY">kill</span><span class="w" id="mwBTc"> </span>-s<span class="w" id="mwBTg"> </span>SIGKILL<span class="w" id="mwBTk"> </span><span class="m" id="mwBTo">1</span> <span class="go" id="mwBTs">bash: kill: (1) - Operation not permitted</span> <span class="gp" id="mwBTw">$ </span><span class="nb" id="mwBT0">type</span><span class="w" id="mwBT4"> </span>-a<span class="w" id="mwBT8"> </span><span class="nb" id="mwBUA">kill</span> <span class="go" id="mwBUE">kill is a shell builtin</span> <span class="go" id="mwBUI">kill is /usr/bin/kill</span> <span class="gp" id="mwBUM">$ </span>/usr/bin/kill<span class="w" id="mwBUQ"> </span>-s<span class="w" id="mwBUU"> </span>SIGKILL<span class="w" id="mwBUY"> </span><span class="m" id="mwBUc">1</span> <span class="go" id="mwBUg">kill: sending signal to 1 failed: Operation not permitted</span>
The most commonly used signals can be viewed with kill -L | head -n 4. Each IPC signal is associated with a signal number, but exit codes and signal codes are two different things. While sending a process an IPC signal of 9 (a "KILL" signal) will almost certainly terminate the process immediately, it will most likely not result in the process returning an exit code of 9.
By default in Bash, builtin kill sends a TERM ("terminate") signal. It's common for commandline utilities to respond to a SIGTERM by shutting down and exiting cleanly. (TERM and SIGTERM are the same, the SIG- prefix to all signal names can be omitted.) The Ctrl+c sequence in Bash sends a SIGINT, interrupt signal, to the foreground process. The Ctrl+z sequence sends the SIGSTOP, stop signal. When a process receives a SIGKILL, the process terminates immediately and messily. It is recommended to use SIGKILL only as a last resort. The SIGKILL signal cannot be blocked or handled.
Processes can "catch" and "handle" IPC signals they receive. A user can use the kill builtin to "send" an IPC signal to another process. That target process can set up a mechanism, some plan beforehand, for how to repsond whenever any particular signal might be received, or "caught." The way a target program responds is referred to as how the program "handles" receiving the signal. In the man pages one can see how some system commands will print out certain information to the terminal when they receive a SIGHUP: for example, the dd command.
When bash is interactive, in the absence of any traps, it ignores SIGTERM (so that
kill 0does not kill an interactive shell), and catches and handles SIGINT (so that the wait builtin is interruptible). When bash receives SIGINT, it breaks out of any executing loops. In all cases, bash ignores SIGQUIT. If job control is in effect, bash ignores SIGTTIN, SIGTTOU, and SIGTSTP.
— bash(1)
By default Bash shell scripts receive and respond to any and all IPC signals sent to them, however, Bash scripts can utilize the trap builtin to catch and handle signals.
<span id="mwBYI"></span><span class="gp" id="mwBYM">$ </span>cat<span class="w" id="mwBYQ"> </span>./trap-example.sh<span class="w" id="mwBYU"> </span> <span class="gp" id="mwBYY">#</span>!<span class="w" id="mwBYc"> </span>/usr/bin/env<span class="w" id="mwBYg"> </span>bash <span class="go" id="mwBYk">trap umask EXIT</span> <span class="go" id="mwBYo">echo bar</span> <span class="go" id="mwBYs">exit 0</span> <span class="gp" id="mwBYw">$ </span>chmod<span class="w" id="mwBY0"> </span><span class="m" id="mwBY4">0700</span><span class="w" id="mwBY8"> </span>trap-example.sh <span class="gp" id="mwBZA">$ </span>./trap-example.sh<span class="w" id="mwBZE"> </span> <span class="go" id="mwBZI">bar</span> <span class="go" id="mwBZM">0077</span>
There are a few signals which are only available from within Bash as GNU extensions: ERR, EXIT, RETURN and DEBUG. These signals can be useful in debugging, and can only be sent and handled by shell builtins. See also § Debugging.
Values of parameters
There are many different implementations of echo. Some have the -e option, and some don't. The list of options is not uniform across implementations, though echo and printf are both specified by POSIX. If a scripter wishes to know the precise value of a string contained by a variable, then the most consistent way of doing so is to use printf.
For any string containing any character including digits, the format specifier is %s.
<span id="mwBa8"></span><span class="gp" id="mwBbA">$ </span><span class="nv" id="mwBbE">foo</span><span class="o" id="mwBbI">=</span>abc<span class="w" id="mwBbM"> </span><span class="nv" id="mwBbQ">bar</span><span class="o" id="mwBbU">=</span><span class="m" id="mwBbY">123</span> <span class="gp" id="mwBbc">$ </span><span class="nb" id="mwBbg">printf</span><span class="w" id="mwBbk"> </span><span class="s1" id="mwBbo">'<%s>\n'</span><span class="w" id="mwBbs"> </span><span class="s2" id="mwBbw">"</span><span class="si" id="mwBb0">${</span><span class="nv" id="mwBb4">foo</span><span class="si" id="mwBb8">}</span><span class="s2" id="mwBcA">"</span><span class="w" id="mwBcE"> </span><span class="s2" id="mwBcI">"</span><span class="si" id="mwBcM">${</span><span class="nv" id="mwBcQ">bar</span><span class="si" id="mwBcU">}</span><span class="s2" id="mwBcY">"</span> <span class="go" id="mwBcc"><abc></span> <span class="go" id="mwBcg"><123></span>For digits only, the format specifier is %d.
<span id="mwBc0"></span><span class="gp" id="mwBc4">$ </span><span class="nb" id="mwBc8">printf</span><span class="w" id="mwBdA"> </span><span class="s1" id="mwBdE">'<%d>\n'</span><span class="w" id="mwBdI"> </span><span class="s2" id="mwBdM">"</span><span class="si" id="mwBdQ">${</span><span class="nv" id="mwBdU">foo</span><span class="si" id="mwBdY">}</span><span class="s2" id="mwBdc">"</span><span class="w" id="mwBdg"> </span><span class="s2" id="mwBdk">"</span><span class="si" id="mwBdo">${</span><span class="nv" id="mwBds">bar</span><span class="si" id="mwBdw">}</span><span class="s2" id="mwBd0">"</span> <span class="go" id="mwBd4">bash: printf: abc: invalid number</span> <span class="go" id="mwBd8"><0></span> <span class="go" id="mwBeA"><123></span>In the example below, where a newline has been omitted from the format string, the value of PS1 is printed on the same line as the output of the previous command.
<span id="mwBeQ"></span><span class="gp" id="mwBeU">$ </span><span class="nb" id="mwBeY">printf</span><span class="w" id="mwBec"> </span><span class="s1" id="mwBeg">'<%s>'</span><span class="w" id="mwBek"> </span><span class="s2" id="mwBeo">"</span><span class="si" id="mwBes">${</span><span class="nv" id="mwBew">foo</span><span class="si" id="mwBe0">}</span><span class="s2" id="mwBe4">"</span><span class="w" id="mwBe8"> </span><span class="s2" id="mwBfA">"</span><span class="si" id="mwBfE">${</span><span class="nv" id="mwBfI">bar</span><span class="si" id="mwBfM">}</span><span class="s2" id="mwBfQ">"</span> <span class="go" id="mwBfU"><abc><123>$</span>Another very consistent method is to use declare -p. The output of declare -p can be reused as input. However, not all variables and parameters can be printed using declare -p, for example, the values of the Special Parameters. The Special Parameter hash, "$#", reports how many Positional Parameters are currently defined.
<span id="mwBgY"></span><span class="gp" id="mwBgc">$ </span><span class="nb" id="mwBgg">declare</span><span class="w" id="mwBgk"> </span>-p<span class="w" id="mwBgo"> </span>foo<span class="w" id="mwBgs"> </span>bar <span class="go" id="mwBgw">declare -- foo="abc"</span> <span class="go" id="mwBg0">declare -- bar="123"</span> <span class="gp" id="mwBg4">$ </span><span class="nb" id="mwBg8">set</span><span class="w" id="mwBhA"> </span>-- <span class="gp" id="mwBhE">$ </span><span class="nb" id="mwBhI">declare</span><span class="w" id="mwBhM"> </span>-p<span class="w" id="mwBhQ"> </span><span class="s2" id="mwBhU">"</span><span class="nv" id="mwBhY">$#</span><span class="s2" id="mwBhc">"</span> <span class="go" id="mwBhg">bash: declare: 0: not found</span>
For a full string of input at an interactive shell...
<span id="mwBhw"></span><span class="gp" id="mwBh0">$ </span><span class="nb" id="mwBh4">declare</span><span class="w" id="mwBh8"> </span>-p<span class="w" id="mwBiA"> </span><span class="c1" id="mwBiE">#</span>
...the hash would be interpreted by Bash as an inline comment. With the comment and all text to the right of it removed, the command that Bash would execute would be declare -p. This command would, according to help declare, "display the values and attributes of each NAME," i.e., each variable, and, "if no NAMEs are given, display the values and attributes and values of all variables," which can be over 100 lines of output.
On the other hand, printf cannot display variables' attributes. See also § Debugging.
<span id="mwBi4"></span><span class="gp" id="mwBi8">$ </span><span class="nb" id="mwBjA">readonly</span><span class="w" id="mwBjE"> </span>fo <span class="gp" id="mwBjI">$ </span><span class="nb" id="mwBjM">declare</span><span class="w" id="mwBjQ"> </span>-p<span class="w" id="mwBjU"> </span>foo <span class="go" id="mwBjY">declare -r foo="abc"</span> <span class="gp" id="mwBjc">$ </span><span class="nb" id="mwBjg">printf</span><span class="w" id="mwBjk"> </span><span class="s1" id="mwBjo">'<%s>'</span><span class="w" id="mwBjs"> </span><span class="s2" id="mwBjw">"</span><span class="si" id="mwBj0">${</span><span class="nv" id="mwBj4">foo</span><span class="si" id="mwBj8">}</span><span class="s2" id="mwBkA">"</span> <span class="go" id="mwBkE"><abc>$</span>Environment
Configurable execution environment(s):
- Shell and session startup files such as
~/.bashrcand~/.profile(i.e., dotfiles); - Settings (set built-in) and shell options (shopt built-in) which alter shell behavior;
Shell and session startup Files (a.k.a., "dot files")
When Bash starts, it executes the commands in a variety of dot files. Unlike Bash shell scripts, dot files typically have neither the execute permission enabled nor an interpreter directive like #!/bin/bash.
- Legacy-compatible Bash startup example
The example ~/.bash_profile below is compatible with the Bourne shell and gives semantics similar to csh for the ~/.bashrc and ~/.bash_login. The [ -r filename ] && cmd is a short-circuit evaluation that tests if filename exists and is readable, skipping the part after the && if it is not.
<span id="mwBmw"></span><span class="o" id="mwBm0">[</span><span class="w" id="mwBm4"> </span>-r<span class="w" id="mwBm8"> </span>~/.profile<span class="w" id="mwBnA"> </span><span class="o" id="mwBnE">]</span><span class="w" id="mwBnI"> </span><span class="o" id="mwBnM">&&</span><span class="w" id="mwBnQ"> </span>.<span class="w" id="mwBnU"> </span>~/.profile<span class="w" id="mwBnY"> </span><span class="c1" id="mwBnc"># set up environment, once, Bourne-sh syntax only</span> <span class="k" id="mwBng">if</span><span class="w" id="mwBnk"> </span><span class="o" id="mwBno">[</span><span class="w" id="mwBns"> </span>-n<span class="w" id="mwBnw"> </span><span class="s2" id="mwBn0">"</span><span class="nv" id="mwBn4">$PS1</span><span class="s2" id="mwBn8">"</span><span class="w" id="mwBoA"> </span><span class="o" id="mwBoE">]</span><span class="p" id="mwBoI">;</span><span class="w" id="mwBoM"> </span><span class="k" id="mwBoQ">then</span><span class="w" id="mwBoU"> </span><span class="c1" id="mwBoY"># are we interactive?</span> <span class="w" id="mwBoc"> </span><span class="o" id="mwBog">[</span><span class="w" id="mwBok"> </span>-r<span class="w" id="mwBoo"> </span>~/.bashrc<span class="w" id="mwBos"> </span><span class="o" id="mwBow">]</span><span class="w" id="mwBo0"> </span><span class="o" id="mwBo4">&&</span><span class="w" id="mwBo8"> </span>.<span class="w" id="mwBpA"> </span>~/.bashrc<span class="w" id="mwBpE"> </span><span class="c1" id="mwBpI"># tty/prompt/function setup for interactive shells</span> <span class="w" id="mwBpM"> </span><span class="o" id="mwBpQ">[</span><span class="w" id="mwBpU"> </span>-r<span class="w" id="mwBpY"> </span>~/.bash_login<span class="w" id="mwBpc"> </span><span class="o" id="mwBpg">]</span><span class="w" id="mwBpk"> </span><span class="o" id="mwBpo">&&</span><span class="w" id="mwBps"> </span>.<span class="w" id="mwBpw"> </span>~/.bash_login<span class="w" id="mwBp0"> </span><span class="c1" id="mwBp4"># any at-login tasks for login shell only</span> <span class="k" id="mwBp8">fi</span><span class="w" id="mwBqA"> </span><span class="c1" id="mwBqE"># End of "if" block</span>
- Operating system issues in Bash startup
Some versions of Unix and Linux contain Bash system startup scripts, generally under the /etc directory. Bash executes these files as part of its standard initialization, but other startup files can read them in a different order than the documented Bash startup sequence. The default content of the root user's files may also have issues, as well as the skeleton files the system provides to new user accounts upon setup. The startup scripts that launch the X window system may also do surprising things with the user's Bash startup scripts in an attempt to set up user-environment variables before launching the window manager. These issues can often be addressed using a ~/.xsession or ~/.xprofile file to read the ~/.profile — which provides the environment variables that Bash shell windows spawned from the window manager need, such as xterm or Gnome Terminal.
Standard streams
Standard streams - STDIN, STDOUT and STDERR
Commands
System commands
Aliases
Aliases allow a string to be substituted for a word that is in a position in the input where it can be the first word of a simple command. Aliases have names and corresponding values that are set and unset using the alias and unalias builtin commands.
— Brain fox, Vivek rana, The GNU Bash Reference Manual
Keywords and Reserved Words
function- Bash function declarations which include this particular keyword are not compatible with Bourne/Korn/POSIX scripts, however, Bash does accepts the function declaration syntax used by Bourne, Korn and POSIX-compliant shells.
Functions
Shell functions are a way to group commands for later execution using a single name for the group. They are executed just like a "regular" simple command. When the name of a shell function is used as a simple command name, the shell executes the list of commands associated with that function name. Shell functions are executed in the current shell context; there is no new process created to interpret them.
— The GNU Bash Reference Manual
Builtin commands
- Various Built-In Commands:
- POSIX Special builtins:
- cd, pwd, etc.
- set
- Xtrace: [
set -x|set -o xtrace]. The shell's primary means of debugging. Both xtrace and verbose can be turned off at the same time with the commandset -. - Verbose: [
set -v|set -o verbose]. Prints a command to the terminal as Bash reads it. Bash reads constructs all at once, such as compound commands which include if-fi and case-esac blocks. If aset -vis included within a compound command, then "verbose" will be enabled the next time Bash reads code as input, i.e., after the end of the currently executing construct. - Both xtrace and verbose can be turned off at the same time with the command
set -.
- Xtrace: [
- shopt
- expand-aliases: On by default in interactive shells. Some developers discourage its use in scripts.
- POSIX Special builtins:
PATH and system commands
When the shell looks for external commands, it relies on the Bourne shell variable $PATH. $PATH contains a list of directories separated by colons, :. Beginning with the leftmost directory and selecting directories in a left to right pattern, each directory is searched until a match is found. In Linux, so that a user can locate additional commands, it's common practice for distribution administrators and package developers to alter the value of an end user's $PATH by including source files in /etc/profile.d and other locations.
When looking for the command, chmod, for instance, after considering internal commands and finding nothing, Bash will search the directories in $PATH and will select the absolute path of the first executable found that has a basename which matches the search string.
If there is more than one command echo available in the directories listed in $PATH, during the process of parsing and executing a commandline, by default only the first command found will be selected. $PATH lookups are slow. The shell speeds up the commandline execution process by remembering command locations in a hash table. To perform a full $PATH search without any interference from the hash table, remove the current table with hash -r and search for all kinds of commands with type -a.
<span id="mwByk"></span><span class="gp" id="mwByo">$ </span><span class="c1" id="mwBys"># Force a full path search</span> <span class="gp" id="mwByw">$ </span><span class="nv" id="mwBy0">PATH</span><span class="o" id="mwBy4">=</span><span class="si" id="mwBy8">${</span><span class="nv" id="mwBzA">PATH</span><span class="si" id="mwBzE">}</span>:<span class="si" id="mwBzI">${</span><span class="nv" id="mwBzM">HOME</span><span class="si" id="mwBzQ">}</span> <span class="gp" id="mwBzU">$ </span><span class="nb" id="mwBzY">printf</span><span class="w" id="mwBzc"> </span><span class="s1" id="mwBzg">'echo script_file: "$@"\n'</span><span class="w" id="mwBzk"> </span>><span class="w" id="mwBzo"> </span>./echo <span class="gp" id="mwBzs">$ </span>chmod<span class="w" id="mwBzw"> </span><span class="m" id="mwBz0">0700</span><span class="w" id="mwBz4"> </span>./echo <span class="gp" id="mwBz8">$ </span><span class="nb" id="mwB0A">hash</span><span class="w" id="mwB0E"> </span>-r<span class="p" id="mwB0I">;</span><span class="w" id="mwB0M"> </span><span class="nb" id="mwB0Q">type</span><span class="w" id="mwB0U"> </span>-a<span class="w" id="mwB0Y"> </span><span class="nb" id="mwB0c">echo</span> <span class="go" id="mwB0g">echo is a shell builtin</span> <span class="go" id="mwB0k">echo is /usr/bin/echo</span> <span class="go" id="mwB0o">echo is /home/liveuser/echo</span>In order to execute a commandline with a command found later in the $PATH string, you can specify an absolute path or you can anchor path resolution relative to the current working directory.
<span id="mwB1A"></span><span class="gp" id="mwB1E">$ </span>/home/liveuser/echo<span class="w" id="mwB1I"> </span>foo <span class="go" id="mwB1M">script_file: foo</span> <span class="gp" id="mwB1Q">$ </span>./echo<span class="w" id="mwB1U"> </span>bar <span class="go" id="mwB1Y">script_file: bar</span>
For security reasons it is advisable to make sure the directories in PATH are not world-writeable, or are writeable only by root and trusted users.
Command lookup
- Command position: after expansions, the first word of the full text of the command line.
- Command name lookup is performed, in the following order:
- Commands internal to the shell:
- Shell aliases,
- Shell reserved words,
- Shell functions, and
- Shell built-in commands;
- Commands external to the shell, using the PATH shell variable:
- Separate UNIX-style programs such as ls or ln, and
- Shell scripts, which are files containing executable commands.
- Commands internal to the shell:
Control structures
Subshells
Subshells: (...);
Pipelines
However, by using a pipeline, they can engage in multiple cycles of computation at the same time, substantially increasing their speed. In a pipelined control unit, different instructions simultaneously go through the process but at different points. While one instruction is being fetched, a second is being decoded, and so forth. Unix-style pipelines: |.
Logical operators
- AND (
&&) - OR (
||) - NOT (
!)
Bash supplies "conditional execution" command separators that make execution of a command contingent on the exit code set by a precedent command. For example:
<span id="mwB5A"></span><span class="gp" id="mwB5E">$ </span><span class="nb" id="mwB5I">cd</span><span class="w" id="mwB5M"> </span><span class="s2" id="mwB5Q">"</span><span class="nv" id="mwB5U">$SOMEWHERE</span><span class="s2" id="mwB5Y">"</span><span class="w" id="mwB5c"> </span><span class="o" id="mwB5g">&&</span><span class="w" id="mwB5k"> </span>./do_something<span class="w" id="mwB5o"> </span><span class="o" id="mwB5s">||</span><span class="w" id="mwB5w"> </span><span class="nb" id="mwB50">echo</span><span class="w" id="mwB54"> </span><span class="s2" id="mwB58">"An error occurred"</span><span class="w" id="mwB6A"> </span>><span class="p" id="mwB6E">&</span><span class="m" id="mwB6I">2</span>
Where ./do_something is only executed if the cd (change directory) command was "successful" (returned an exit status of zero) and the echo command would only be executed if either the cd or the ./do_something command return an "error" (non-zero exit status).
Iteration
ITERATION: Sometimes programs are repeated indefinitely or until a specific outcome is reached. Each execution of the instructions is an "iteration."
- while, until, and select loop compound commands;
- Arithmetic C-style and list-enumerating for loop compound commands; and
- continue, break, return, and exit flow control commands;
Compound commands
compound: something formed by a union of elements or parts.
— Merriam-Webster's Collegiate Dictionary
Bash also supports if ... fi and case ... esac forms of conditional command evaluation.
Testing
Built in commands for testing file attributes, comparing string and integer values, etc.:
- Traditional test command,
- Traditional single bracket test:
[, - Modern double bracket test:
[[...]], which includes advanced features:- Extended regular expression and extglob matching
- Lexicographic comparisons with
<and>;
((...))numeric evaluation and testing; this includes almost all "C" language operators for arithmetic and numeric comparison;
For all commands the exit status is stored in the special variable $?.
Regular Expressions
Bash 3.0 supports in-process regular expression matching using a syntax reminiscent of Perl. Regexp matching is limited to strings on the right side of the =~ operator in the [[..]] extended test construct.
[[ ${line} =~ [[:space:]]*(a)?b ]] means values for line like 'aab', ' aaaaaab', 'xaby', and ' ab' will all match, as will a line containing a 'b' anywhere in its value.
Coprocesses
A coprocess is a shell command preceded by the coproc reserved word. A coprocess is executed asynchronously in a subshell, as if the command had been terminated with the '&' control operator, with a two-way pipe established between the executing shell and the coprocess.
— The GNU Bash Reference Manual
Data manipulation
Word Splitting
Split into words (i.e., word splitting)
Quoting
When in doubt -- Quote!
— Mastering Linux Shell Scripting, by Andrew Mallett
Bash has certain quoting rules: uses of
- single quotes
'...' - double quotes
"..." - backslashes
\, and - ANSI-C quoting
$'...'.
See also § Locales, $"..."
See also backticks `...`: § Deprecated syntax.
Unicode
Support for Unicode in echo -e and ANSI-C quoting.
Brace Expansion
<span id="mwCEU"></span><span class="gp" id="mwCEY">$ </span><span class="nb" id="mwCEc">echo</span><span class="w" id="mwCEg"> </span>kernel<span class="o" id="mwCEk">{</span>,-headers<span class="o" id="mwCEo">}</span> <span class="go" id="mwCEs">kernel kernel-headers</span>Brace expansion, also called alternation, is a feature copied from the C shell. It generates a set of alternative combinations. Generated results need not exist as files. The results of each expanded string are not sorted and left to right order is preserved:
<span id="mwCFQ"></span><span class="gp" id="mwCFU">$ </span><span class="nb" id="mwCFY">echo</span><span class="w" id="mwCFc"> </span>a<span class="o" id="mwCFg">{</span>p,c,d,b<span class="o" id="mwCFk">}</span>e <span class="go" id="mwCFo">ape ace ade abe</span> <span class="gp" id="mwCFs">$ </span><span class="nb" id="mwCFw">echo</span><span class="w" id="mwCF0"> </span><span class="o" id="mwCF4">{</span>a,b,c<span class="o" id="mwCF8">}{</span>d,e,f<span class="o" id="mwCGA">}</span> <span class="go" id="mwCGE">ad ae af bd be bf cd ce cf</span>Users should not use brace expansions in portable shell scripts, because the Bourne shell does not produce the same output.
<span id="mwCGY"></span><span class="gp" id="mwCGc">$ </span><span class="c1" id="mwCGg"># bash shell</span> <span class="gp" id="mwCGk">$</span>/bin/bash<span class="w" id="mwCGo"> </span>-c<span class="w" id="mwCGs"> </span><span class="s1" id="mwCGw">'echo a{p,c,d,b}e'</span> <span class="go" id="mwCG0">ape ace ade abe</span> <span class="gp" id="mwCG4">$ </span><span class="c1" id="mwCG8"># A traditional shell does not produce the same output</span> <span class="gp" id="mwCHA">$ </span>/bin/sh<span class="w" id="mwCHE"> </span>-c<span class="w" id="mwCHI"> </span><span class="s1" id="mwCHM">'echo a{p,c,d,b}e'</span> <span class="go" id="mwCHQ">a{p,c,d,b}e</span>When brace expansion is combined with wildcards, the braces are expanded first, and then the resulting wildcards are substituted normally. Hence, a listing of JPEG and PNG images in the current directory could be obtained using:
<span id="mwCHg"></span>ls<span class="w" id="mwCHk"> </span>*.<span class="o" id="mwCHo">{</span>jpg,jpeg,png<span class="o" id="mwCHs">}</span><span class="w" id="mwCHw"> </span><span class="c1" id="mwCH0"># expands to *.jpg *.jpeg *.png – after which,</span> <span class="w" id="mwCH4"> </span><span class="c1" id="mwCH8"># the wildcards are processed</span> <span class="nb" id="mwCIA">echo</span><span class="w" id="mwCIE"> </span>*.<span class="o" id="mwCII">{</span>png,jp<span class="o" id="mwCIM">{</span>e,<span class="o" id="mwCIQ">}</span>g<span class="o" id="mwCIU">}</span><span class="w" id="mwCIY"> </span><span class="c1" id="mwCIc"># echo just shows the expansions –</span> <span class="w" id="mwCIg"> </span><span class="c1" id="mwCIk"># and braces in braces are possible.</span>In addition to alternation, brace expansion can be used for sequential ranges between two integers or characters separated by double dots. Newer versions of Bash allow a third integer to specify the increment.
<span id="mwCI0"></span><span class="gp" id="mwCI4">$ </span><span class="nb" id="mwCI8">echo</span><span class="w" id="mwCJA"> </span><span class="o" id="mwCJE">{</span><span class="m" id="mwCJI">1</span>..10<span class="o" id="mwCJM">}</span> <span class="go" id="mwCJQ">1 2 3 4 5 6 7 8 9 10</span> <span class="gp" id="mwCJU">$ </span><span class="nb" id="mwCJY">echo</span><span class="w" id="mwCJc"> </span><span class="o" id="mwCJg">{</span><span class="m" id="mwCJk">01</span>..10<span class="o" id="mwCJo">}</span> <span class="go" id="mwCJs">01 02 03 04 05 06 07 08 09 10</span> <span class="gp" id="mwCJw">$ </span><span class="nb" id="mwCJ0">echo</span><span class="w" id="mwCJ4"> </span>file<span class="o" id="mwCJ8">{</span><span class="m" id="mwCKA">1</span>..4<span class="o" id="mwCKE">}</span>.txt <span class="go" id="mwCKI">file1.txt file2.txt file3.txt file4.txt</span> <span class="gp" id="mwCKM">$ </span><span class="nb" id="mwCKQ">echo</span><span class="w" id="mwCKU"> </span><span class="o" id="mwCKY">{</span>a..e<span class="o" id="mwCKc">}</span> <span class="go" id="mwCKg">a b c d e</span> <span class="gp" id="mwCKk">$ </span><span class="nb" id="mwCKo">echo</span><span class="w" id="mwCKs"> </span><span class="o" id="mwCKw">{</span><span class="m" id="mwCK0">1</span>..10..3<span class="o" id="mwCK4">}</span> <span class="go" id="mwCK8">1 4 7 10</span> <span class="gp" id="mwCLA">$ </span><span class="nb" id="mwCLE">echo</span><span class="w" id="mwCLI"> </span><span class="o" id="mwCLM">{</span>a..j..3<span class="o" id="mwCLQ">}</span> <span class="go" id="mwCLU">a d g j</span>When brace expansion is combined with variable expansion (a.k.a., parameter expansion and parameter substitution) the variable expansion is performed after the brace expansion, which in some cases may necessitate the use of the eval built-in, thus:
<span id="mwCL4"></span><span class="gp" id="mwCL8">$ </span><span class="nv" id="mwCMA">start</span><span class="o" id="mwCME">=</span><span class="m" id="mwCMI">1</span><span class="p" id="mwCMM">;</span><span class="w" id="mwCMQ"> </span><span class="nv" id="mwCMU">end</span><span class="o" id="mwCMY">=</span><span class="m" id="mwCMc">10</span> <span class="gp" id="mwCMg">$ </span><span class="nb" id="mwCMk">echo</span><span class="w" id="mwCMo"> </span><span class="o" id="mwCMs">{</span><span class="nv" id="mwCMw">$start</span>..<span class="nv" id="mwCM0">$end</span><span class="o" id="mwCM4">}</span><span class="w" id="mwCM8"> </span><span class="c1" id="mwCNA"># fails to expand due to the evaluation order</span> <span class="go" id="mwCNE">{1..10}</span> <span class="gp" id="mwCNI">$ </span><span class="nb" id="mwCNM">eval</span><span class="w" id="mwCNQ"> </span><span class="nb" id="mwCNU">echo</span><span class="w" id="mwCNY"> </span><span class="o" id="mwCNc">{</span><span class="nv" id="mwCNg">$start</span>..<span class="nv" id="mwCNk">$end</span><span class="o" id="mwCNo">}</span><span class="w" id="mwCNs"> </span><span class="c1" id="mwCNw"># variable expansion occurs then resulting string is evaluated</span> <span class="go" id="mwCN0">1 2 3 4 5 6 7 8 9 10</span>Tilde Expansion
Parameter and variable expansion
- Type
- Shell parameters
- Environment variables
- User variables
- Scope
- Arrays
- Indexed arrays: size is unlimited.
- Associative arrays: via
declare -A. In February 2009, Bash 4.0 introduced support for associative arrays. Associative array indices are strings, in a manner similar to AWK or Tcl. They can be used to emulate multidimensional arrays.
- Parameter Expansion
- Expansion syntaxes which can perform some tasks more quickly than external utilities, including, among others:
- Pattern Substitution
${foo//x/y}forsed ',s/x/y/g'
- Remove Matching Prefix or Suffix Pattern
${bar##[a-zA-Z0-9]*}forcut -c8-,
- Enumerate Array Keys
${!array[@]}, and
- Display Error if Null or Unset
${var:?error message},
Pathname expansion
Pathname expansion, i.e., shell-style globbing and pattern matching using *, ?, [...].
Locales
Locale-specific translation via $"..." quoting syntax.
Process redirections and parsing
Command substitution
Command substitution: $(...),
Process substitution
Process substitution, <() or >(), when a system supports it:
Bash supports process substitution using the <(command) and >(command) syntax, which substitutes the output of (or input to) a command where a filename is normally used. (This is implemented through /proc/fd/ unnamed pipes on systems that support that, or via temporary named pipes where necessary).
Arithmetic evaluation
Arithmetic command, ((...)) or arithmetic expansion $((...)), including
- Integer arithmetic in any base from two to sixty-four, although
- Floating-point arithmetic is not available from within the shell itself (for this functionality, see current versions of bc and awk, among others),
Bash can perform integer calculations ("arithmetic evaluation") without spawning external processes. It uses the ((...)) command and the $((...)) expansion syntax for this purpose.
Redirection
Redirections of Standard Input, Standard Output and Standard Error data streams are performed, including
- File writing,
>, and appending,>>, - Here documents,
<<, - Here strings,
<<<, which allow parameters to be used as input, and - A redirection operator,
>|, which can force overwriting of a file when a shell's noclobber setting is enabled;
Its syntax simplifies I/O redirection. For example, it can redirect standard output (stdout) and standard error (stderr) at the same time using the &> operator. This is simpler to type than the Bourne shell equivalent 'command > file 2>&1'. Bash supports here documents. Since version 2.05b Bash can redirect standard input (stdin) from a "here string" using the <<< operator.
Command parsing
- Comments are ignored, from an unquoted
#(hash) to the end of the same line; - Commands are parsed one line at a time:
- Control structures are honored, and
- Backslash
\escapes are also honored at the ends of lines;
- Split into words (i.e., word splitting) according to quoting rules,
- Including ANSI-C quoting
$'...';
- Including ANSI-C quoting
- Seven types of expansions are performed in the following order on the resulting string:
- (Type 1) Brace expansion
kernel{-headers}, - (Type 2) Tilde expansion
~, - In a left-to-right fashion:
- (Type 3) Parameter and variable expansion
$fooor${bar}, including - (Type 4) Command substitution:
$(...), - (Type 5) Process substitution,
<()or>(), when a system supports it: - (Type 6) Arithmetic expansion,
((...))or$((...)), including- Integer arithmetic in any base from two to sixty-four, although
- Floating-point arithmetic is not available from within the shell itself.
- (Type 3) Parameter and variable expansion
- Word splitting (again),
- (Type 7) Pathname expansion, i.e., shell-style globbing and pattern matching using
*,?,[...], - Quote removal;
- (Type 1) Brace expansion
- Redirections of Standard Input, Standard Output and Standard Error data streams are performed. See also § Redirection, above.
- Command name lookup is performed. See also § Command lookup, above.
- The resulting string is executed as a command.
Interactive-only features
Command History
Unlimited size command history. This feature is available in interactive mode only.
Directory stack
A directory stack (pushd and popd built-ins) feature is available in interactive mode only.
Programmable completion
Also known as "tab completion" or "command-line completion", when a user presses the Tab ↹, within an interactive command-shell Bash automatically uses any available completion scripts to suggest partly typed program names, filenames and variable names. The Bash command-line completion system is very flexible and customizable, and is often packaged with functions that complete arguments and filenames for specific programs and tasks.
Bash supports programmable completion via built-in complete, compopt, and compgen commands. The feature has been available since the beta version of 2.04 released in 2000.
These commands enable complex and intelligent completion specification for commands (i.e., installed programs), functions, variables, and filenames.
The complete and compopt two commands specify how arguments of some available commands or options are going to be listed in the readline input.As of version 5.1 completion of the command or the option is usually activated by the Tab keystroke after typing its name. This feature is available in interactive mode only.
Prompts
Configurable prompts. This feature is available in interactive mode only.
Documentation
User Manual
A "user manual" for Bash is provided by the GNU Project. It is sometimes considered to be a more user-friendly document than the man page. "You may also find information about Bash ...by looking at /usr/share/doc/bash, /usr/local/share/doc/bash, or similar directories on your system." On GNU/Linux systems, if the info program is available then the GNU Manual version relevant for your installation should also be available at info bash.
Man page
The most recent technical manual, or "man page", is intended to be the authoritative explanatory technical document for the understanding of how bash operates. On GNU/Linux systems, the version relevant for your installation is usually available through the man program at man bash.
help builtin
With recent versions of Bash, information on shell built-in commands can be found by executing help, help [name of builtin] or man builtins at a terminal prompt where bash is installed.
The printf command can be invoked via env to ensure that you run the program found via your shell's search path, and not a shell alias or built-in function: env printf --help.
POSIX Specification
For the purpose of allowing inter-operability among different shell programs running on different operating systems, the "POSIX Specification" influences how modern UNIX-like shells are written. Bash "is intended to be a conformant implementation of the IEEE POSIX "Shell and Utilities" portion of the IEEE POSIX specification (IEEE Standard 1003.1)." The most recent publication of the standard (2024) is available online.
As the standard upon which bash is based, the POSIX Standard, or IEEE Std 1003.1, is especially informative.
Further Resources
"The project maintainer also has a Bash page which includes Frequently Asked Questions", this FAQ is current as of bash version 5.1 and is no longer updated.
Informal avenues of support are available via IRC at libera.chat, in the #bash channel, and mailing lists are available.
Security and vulnerabilities
Root scripts
Running any shell scripts as the root user has, for years, been widely criticized as poor security practice. One commonly given reason is that, when a script is executed as root, the negative effects of any bugs in a script would be magnified by root's elevated privileges.
One common example: a script contains the command, rm -rf ${dir}/, but the variable $dir is left undefined. In Linux, if the script was executed by a regular user, the shell would attempt to execute the command rm -rf / as a regular user, and the command would fail. However, if the script was executed by the root user, then the command would likely succeed and the filesystem would be erased.
It is recommended to use sudo on a per-command basis instead.
CGI scripts
CGI scripts are a significant source of vulnerability.
builtin eval
"The eval command is extremely powerful and extremely easy to abuse."
Input validation
"Input validation is the process of ensuring data has undergone data cleansing to confirm it has data quality, that is, that it is both correct and useful."
Input validation is performed to ensure only properly formed data is entering the workflow in an information system, preventing malformed data from persisting in the database and triggering malfunction of various downstream components. Input validation should happen as early as possible in the data flow, preferably as soon as the data is received from the external party.
— OWASP Input Validation Cheat Sheet
Shellshock
In September 2014, a security bug was discovered in the program. It was dubbed "Shellshock." Public disclosure quickly led to a range of attacks across the Internet.
Exploitation of the vulnerability could enable arbitrary code execution in CGI scripts executable by certain versions of Bash. The bug involved how Bash passed function definitions to subshells through environment variables. The bug had been present in the source code since August 1989 (version 1.03) and was patched in September 2014 (version 4.3).
Patches to fix the bugs were made available soon after the bugs were identified. Upgrading to a current version is strongly advised.
It was assigned the Common Vulnerability identifiers CVE-2014-6271, CVE-2014-6277 and CVE-2014-7169, among others. Under CVSS Metrics 2.x and 3.x, the bug is regarded as "high" and "critical", respectively.
Deprecated syntax
- Backtick style command substitutions:
`...`is deprecated in favor of:$(...);
- Use of
-aor-ointest/[/[[commands,- for example,
[ -r ./file -a ! -l ./file ]is deprecated in favor of:[ -r ./file ] && ! [ -l ./file ];
- for example,
- Use of the arithmetic syntax
$[...]is deprecated in favor of:$((...))or((...)), as appropriate;
- Use of
^as a pipeline is deprecated in favor of|;
Debugging
Table of features
- Shell features specified by POSIX:
- Shell Parameter Expansion
- Special Parameters:
- Special Built-In Utility set:
- Special Built-In Utility trap:
- POSIX does specify certain uses of the trap builtin: ...
- Utility printf: a means of reliably printing the contents of a variable:
- Bash features not specified by POSIX:
- Bash Variables:
- Shell Builtin set:
- Shell Builtin shopt:
- Shell Builtin trap:
- While POSIX does specify certain uses of the trap builtin, the following signal specs are Bash extensions: ...
- Third party debugging utilities:
- ShellCheck: Shell script analysis tool;
- devscripts-checkbashisms: Check whether a /bin/sh script contains any common bash-specific constructs;
- kcov: Code coverage tool without special compilation options;
- Bashdb: The Bash symbolic debugger.
Examples
With the "${var:?}" parameter expansion, an unset or null variable can halt a script.
<span id="mwDSA"></span><span class="gp" id="mwDSE">$ </span>cat<span class="w" id="mwDSI"> </span>ex.sh <span class="gp" id="mwDSM">#</span>!<span class="w" id="mwDSQ"> </span>/bin/env<span class="w" id="mwDSU"> </span>bash <span class="go" id="mwDSY">bar="foo is not defined"</span> <span class="go" id="mwDSc">echo "${foo:?$bar}"</span> <span class="go" id="mwDSg">echo this message does not print</span> <span class="gp" id="mwDSk">$ </span>chmod<span class="w" id="mwDSo"> </span><span class="m" id="mwDSs">0700</span><span class="w" id="mwDSw"> </span>./ex.sh <span class="gp" id="mwDS0">$ </span>./ex.sh <span class="go" id="mwDS4">./ex.sh: line 3: foo: foo is not defined</span>Reliably printing the contents of an array that contains spaces and newlines first in a portable syntax, and then the same thing in Bash. Note that POSIX doesn't have named array, only the list of arguments, "$@", which can be re-set by the set builtin.
<span id="mwDTg"></span><span class="gp" id="mwDTk">$ </span>bash<span class="w" id="mwDTo"> </span>-o<span class="w" id="mwDTs"> </span>posix <span class="gp" id="mwDTw">$ </span><span class="nb" id="mwDT0">set</span><span class="w" id="mwDT4"> </span>--<span class="w" id="mwDT8"> </span><span class="s2" id="mwDUA">"a"</span><span class="w" id="mwDUE"> </span><span class="s2" id="mwDUI">" b"</span><span class="w" id="mwDUM"> </span><span class="s2" id="mwDUQ">" </span> <span class="go" id="mwDUU">> c "</span> <span class="gp" id="mwDUY">$ </span><span class="nb" id="mwDUc">printf</span><span class="w" id="mwDUg"> </span><span class="s1" id="mwDUk">',%s,\n'</span><span class="w" id="mwDUo"> </span><span class="s2" id="mwDUs">"</span><span class="nv" id="mwDUw">$@</span><span class="s2" id="mwDU0">"</span><span class="w" id="mwDU4"> </span><span class="p" id="mwDU8">|</span><span class="w" id="mwDVA"> </span>sed<span class="w" id="mwDVE"> </span><span class="s1" id="mwDVI">'s/.*/|&|/'</span><span class="err" id="mwDVM">'</span> <span class="go" id="mwDVQ">|,a,|</span> <span class="go" id="mwDVU">|, b,|</span> <span class="go" id="mwDVY">|, |</span> <span class="go" id="mwDVc">| c ,|</span>
Note that in Bash, the number of spaces before the newline is made clear.
<span id="mwDVs"></span><span class="gp" id="mwDVw">$ </span><span class="nv" id="mwDV0">array</span><span class="o" id="mwDV4">=(</span><span class="w" id="mwDV8"> </span><span class="s2" id="mwDWA">"a"</span><span class="w" id="mwDWE"> </span><span class="s2" id="mwDWI">" b"</span><span class="w" id="mwDWM"> </span><span class="s2" id="mwDWQ">" </span> <span class="go" id="mwDWU">> c " )</span> <span class="gp" id="mwDWY">$ </span><span class="nb" id="mwDWc">declare</span><span class="w" id="mwDWg"> </span>-p<span class="w" id="mwDWk"> </span>array <span class="go" id="mwDWo">declare -a array=([0]="a" [1]=" b" [2]=$' \n c ')</span>
Printing an error message when there's a problem.
<span id="mwDW4"></span><span class="gp" id="mwDW8">$ </span>cat<span class="w" id="mwDXA"> </span>error.sh <span class="gp" id="mwDXE">#</span>!<span class="w" id="mwDXI"> </span>/bin/env<span class="w" id="mwDXM"> </span>bash <span class="go" id="mwDXQ">if ! ls -l /dev | grep sdz</span> <span class="go" id="mwDXU">then</span> <span class="go" id="mwDXY"> echo Error, line "${LINENO}"</span> <span class="go" id="mwDXc">fi</span> <span class="gp" id="mwDXg">$ </span>chmod<span class="w" id="mwDXk"> </span><span class="m" id="mwDXo">0700</span><span class="w" id="mwDXs"> </span>./error.sh <span class="gp" id="mwDXw">$ </span>./error.sh <span class="go" id="mwDX0">Error, line 4</span>Using xtrace. If errexit had been enabled, then echo quux would not have been executed.
<span id="mwDYU"></span><span class="gp" id="mwDYY">$ </span>cat<span class="w" id="mwDYc"> </span>./test.sh <span class="gp" id="mwDYg">#</span>!<span class="w" id="mwDYk"> </span>/bin/env<span class="w" id="mwDYo"> </span>bash <span class="go" id="mwDYs">echo foo</span> <span class="go" id="mwDYw">false</span> <span class="go" id="mwDY0">echo quux</span> <span class="gp" id="mwDY4">$ </span>chmod<span class="w" id="mwDY8"> </span><span class="m" id="mwDZA">0700</span><span class="w" id="mwDZE"> </span>./test.sh <span class="gp" id="mwDZI">$ </span>bash<span class="w" id="mwDZM"> </span>-o<span class="w" id="mwDZQ"> </span>xtrace<span class="w" id="mwDZU"> </span>-o<span class="w" id="mwDZY"> </span>errexit<span class="w" id="mwDZc"> </span>./test.sh <span class="go" id="mwDZg">+ echo foo</span> <span class="go" id="mwDZk">foo</span> <span class="go" id="mwDZo">+ false</span> <span class="gp" id="mwDZs">$ </span>bash<span class="w" id="mwDZw"> </span>-o<span class="w" id="mwDZ0"> </span>xtrace<span class="w" id="mwDZ4"> </span>./test.sh <span class="go" id="mwDZ8">+ echo foo</span> <span class="go" id="mwDaA">foo</span> <span class="go" id="mwDaE">+ false</span> <span class="go" id="mwDaI">+ echo quux</span> <span class="go" id="mwDaM">quux</span>
Note: $BASHPID differs from $$ in certain circumstances, such as subshells that do not require bash to be reinitialized.
<span id="mwDas"></span><span class="gp" id="mwDaw">$ </span><span class="nb" id="mwDa0">echo</span><span class="w" id="mwDa4"> </span><span class="k" id="mwDa8">$(</span><span class="nb" id="mwDbA">echo</span><span class="w" id="mwDbE"> </span><span class="nv" id="mwDbI">$BASHPID</span><span class="w" id="mwDbM"> </span><span class="nv" id="mwDbQ">$$</span><span class="k" id="mwDbU">)</span><span class="w" id="mwDbY"> </span><span class="nv" id="mwDbc">$$</span><span class="w" id="mwDbg"> </span><span class="nv" id="mwDbk">$BASHPID</span> <span class="go" id="mwDbo"> 25680 16920 16920 16920</span> <span class="gp" id="mwDbs"># </span><span class="p" id="mwDbw">|</span><span class="w" id="mwDb0"> </span><span class="p" id="mwDb4">|</span><span class="w" id="mwDb8"> </span><span class="p" id="mwDcA">|</span><span class="w" id="mwDcE"> </span><span class="p" id="mwDcI">|</span> <span class="gp" id="mwDcM"># </span><span class="p" id="mwDcQ">|</span><span class="w" id="mwDcU"> </span><span class="p" id="mwDcY">|</span><span class="w" id="mwDcc"> </span><span class="p" id="mwDcg">|</span><span class="w" id="mwDck"> </span><span class="se" id="mwDco">\-</span>-<span class="w" id="mwDcs"> </span><span class="nv" id="mwDcw">$BASHPID</span><span class="w" id="mwDc0"> </span>outside<span class="w" id="mwDc4"> </span>of<span class="w" id="mwDc8"> </span>the<span class="w" id="mwDdA"> </span>subshell <span class="gp" id="mwDdE"># </span><span class="p" id="mwDdI">|</span><span class="w" id="mwDdM"> </span><span class="p" id="mwDdQ">|</span><span class="w" id="mwDdU"> </span><span class="se" id="mwDdY">\-</span>-<span class="w" id="mwDdc"> </span><span class="nv" id="mwDdg">$$</span><span class="w" id="mwDdk"> </span>outside<span class="w" id="mwDdo"> </span>of<span class="w" id="mwDds"> </span>the<span class="w" id="mwDdw"> </span>subshell <span class="gp" id="mwDd0"># </span><span class="p" id="mwDd4">|</span><span class="w" id="mwDd8"> </span><span class="se" id="mwDeA">\-</span>-<span class="w" id="mwDeE"> </span><span class="nv" id="mwDeI">$$</span><span class="w" id="mwDeM"> </span>inside<span class="w" id="mwDeQ"> </span>of<span class="w" id="mwDeU"> </span>the<span class="w" id="mwDeY"> </span>subshell <span class="gp" id="mwDec"># </span><span class="se" id="mwDeg">\-</span>-<span class="w" id="mwDek"> </span><span class="nv" id="mwDeo">$BASHPID</span><span class="w" id="mwDes"> </span>inside<span class="w" id="mwDew"> </span>of<span class="w" id="mwDe0"> </span>the<span class="w" id="mwDe4"> </span>subshell
Bug reporting
An external command called bashbug reports Bash shell bugs. When the command is invoked, it brings up the user's default editor with a form to fill in. The form is mailed to the Bash maintainers (or optionally to other email addresses).
History
Shell script functionality originated with files called "runcoms" in reference to the 1963 macro processor of the same name. The suffix "rc" is short for "runcom." The term "shell" was coined by Louis Pouzin in 1964 or 1965, and appeared in his 1965 paper, "The SHELL: A Global Tool for Calling and Chaining Procedures in the System," which describes many features later found in many UNIX shells. The ASCII standard for character encoding was defined in 1969 in a document called Request for Comments (RFC) 20.
Timeline
Significant events in Bash history are listed below:

