{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"The Bash Hackers Wiki","text":"

Under construction

This is an archive of the old wiki.bash-hackers.org with the goal of preserving and improving the content by the community in a modern way and format.

The most recent version of each page that had content was automatically converted to Markdown and can be found here. Pandoc did its best, but there is still some work to do as not all pages are formatted correctly. So for everyone who is interested in helping out, feel free to open PRs. Any help is welcome.

This wiki is intended to hold documentation of any kind about GNU Bash. The main motivation was to provide human-readable documentation and information so users aren't forced to read every bit of the Bash manpage - which can be difficult to understand. However, the docs here are not meant as a newbie tutorial.

This wiki and any programs found in this wiki are free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This wiki and its programs are distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Stranger! Feel free to comment or edit the contents on GitHub. Use GitHub Issues to submit bugs and GitHub Discussions for enhancements, requests and general feedback/discussion.

","tags":["bash","shell","linux","scripting"]},{"location":"#scripting-and-general-information","title":"Scripting and general information","text":"","tags":["bash","shell","linux","scripting"]},{"location":"#code-snippets","title":"Code snippets","text":"

There is a section that holds small code snippets.

See also some Bash source code excerpts.

","tags":["bash","shell","linux","scripting"]},{"location":"#how-to","title":"How to","text":"

Doing specific tasks: concepts, methods, ideas:

","tags":["bash","shell","linux","scripting"]},{"location":"#bash-syntax-and-operations","title":"Bash syntax and operations","text":"","tags":["bash","shell","linux","scripting"]},{"location":"#compound-commands","title":"Compound commands","text":"Compound commands overview Grouping { ...; } command grouping ( ... ) command grouping in a subshell Conditionals [[ ... ]] conditional expression if ...; then ...; fi conditional branching case ... esac pattern-based branching Loops for word in ...; do ...; done classic for-loop for ((x=1; x<=10; x++)); do ...; done C-style for-loop while ...; do ...; done while loop until ...; do ...; done until loop Misc (( ... )) arithmetic evaluation select word in ...; do ...; done user selections","tags":["bash","shell","linux","scripting"]},{"location":"#expansions-and-substitutions","title":"Expansions and substitutions","text":"Introduction to expansions and substitutions {A,B,C} {A..C} Brace expansion ~/ ~root/ Tilde expansion $FOO ${BAR%.mp3} Parameter expansion `command` $(command) Command substitution <(command.md) >(command) Process substitution $((1 + 2 + 3)) $[4 + 5 + 6] Arithmetic expansion Hello <---> Word! Word splitting /data/*-av/*.mp? Pathname expansion","tags":["bash","shell","linux","scripting"]},{"location":"#builtin-commands","title":"Builtin Commands","text":"

This is a selection of builtin commands and command-like keywords, loosely arranged by their common uses. These are provided directly by the shell, rather than invoked as standalone external commands.

","tags":["bash","shell","linux","scripting"]},{"location":"#declaration-commands","title":"Declaration commands","text":"

Note

Commands that set and query attributes/types, and manipulate simple datastructures.

Command Description Alt Type declare Display or set shell variables or functions along with attributes. typeset builtin export Display or set shell variables, also giving them the export attribute. typeset -x special builtin eval Evaluate arguments as shell code. special builtin local Declare variables as having function local scope. builtin readonly Mark variables or functions as read-only. typeset -r special builtin unset Unset variables and functions. special builtin shift Shift positional parameters special builtin","tags":["bash","shell","linux","scripting"]},{"location":"#io","title":"IO","text":"

Note

Commands for reading/parsing input, or producing/formatting output of standard streams.

Command Description Alt Type coproc Co-processes: Run a command in the background with pipes for reading / writing its standard streams. keyword echo Create output from arguments. builtin mapfile Read lines of input into an array. readarray builtin printf \"advanced echo\" builtin read Read input into variables or arrays, or split strings into fields using delimiters. builtin","tags":["bash","shell","linux","scripting"]},{"location":"#configuration-and-debugging","title":"Configuration and Debugging","text":"

Note

Commands that modify shell behavior, change special options, assist in debugging.

Command Description Alt Type caller Identify/print execution frames. builtin set Set the positional parameters and/or set options that affect shell behaviour. special builtin shopt set/get some bash-specific shell options. builtin","tags":["bash","shell","linux","scripting"]},{"location":"#control-flow-and-data-processing","title":"Control flow and data processing","text":"

Note

Commands that operate on data and/or affect control flow.

Command Description Alt Type colon \"true\" null command. true special builtin . (dot) Source external files. source special builtin false Fail at doing nothing. builtin continue / break continue with or break out of loops. special builtin let Arithmetic evaluation simple command. builtin return Return from a function with a specified exit status. special builtin [] The classic test simple command. test builtin","tags":["bash","shell","linux","scripting"]},{"location":"#process-and-job-control","title":"Process and Job control","text":"

Note

Commands related to jobs, signals, process groups, subshells.

Command Description Alt Type exec Replace the current shell process or set redirections. special builtin exit Exit the shell. special builtin trap Set signal handlers or output the current handlers. special builtin kill Send a signal to specified process(es.md) builtin times Display process times. special builtin wait Wait for background jobs and asynchronous lists. builtin","tags":["bash","shell","linux","scripting"]},{"location":"#dictionary","title":"Dictionary","text":"

A list of expressions, words, and their meanings can be found under the Dict tab.

","tags":["bash","shell","linux","scripting"]},{"location":"#links","title":"Links","text":"","tags":["bash","shell","linux","scripting"]},{"location":"#official-bash-links","title":"Official Bash links","text":"","tags":["bash","shell","linux","scripting"]},{"location":"#recommended-shell-resources","title":"Recommended Shell resources","text":"","tags":["bash","shell","linux","scripting"]},{"location":"#documentation-reference","title":"Documentation / Reference","text":"","tags":["bash","shell","linux","scripting"]},{"location":"#assorted-interesting-links","title":"Assorted interesting links","text":"","tags":["bash","shell","linux","scripting"]},{"location":"#bash-libraries-needs-review","title":"Bash Libraries (needs review)","text":"","tags":["bash","shell","linux","scripting"]},{"location":"#contact","title":"Contact","text":"

Visit us in ircs://irc.libera.chat:6697, channel #bash ;-)

If you have critiques or suggestions, please feel free to send a mail using the contact form on the right. Note that there is a simple discussion option below every article.

Please also see the imprint if you have problems with the site and its contents (legality, ...)!

It also would be nice to drop a line when

Simply: Reader's feedback.

","tags":["bash","shell","linux","scripting"]},{"location":"bash4/","title":"Bash 4 - a rough overview","text":"

Attention

Since Bash 4 has been around for quite some time now (4.3 will come soon), I consider it to be \"standard\". This page is not maintained anymore and is left here to keep your links working. See the bashchanges page for new stuff introduced.

Besides many bugfixes since Bash 3.2, Bash 4 will bring some interesting new features for shell users and scripters. See also bashchanges for a small general overview with more details.

Not all of the changes and news are included here, just the biggest or most interesting ones. The changes to completion, and the readline component are not covered. Though, if you're familiar with these parts of Bash (and Bash 4), feel free to write a chapter here.

The complete list of fixes and changes is in the CHANGES or NEWS file of your Bash 4 distribution.

The current available stable version is 4.4.18 release (February 03, 2018):

"},{"location":"bash4/#new-or-changed-commands-and-keywords","title":"New or changed commands and keywords","text":""},{"location":"bash4/#the-new-coproc-keyword","title":"The new \"coproc\" keyword","text":"

Bash 4 introduces the concepts of coprocesses, a well known feature of other shells. The basic concept is simple: It will start any command in the background and set up an array that is populated with accessible files that represent the filedescriptors of the started process.

In other words: It lets you start a process in background and communicate with its input and output data streams.

See The coproc keyword

"},{"location":"bash4/#the-new-mapfile-builtin","title":"The new \"mapfile\" builtin","text":"

The mapfile builtin is able to map the lines of a file directly into an array. This avoids having to fill an array yourself using a loop. It enables you to define the range of lines to read, and optionally call a callback, for example to display a progress bar.

See: mapfile

"},{"location":"bash4/#changes-to-the-case-keyword","title":"Changes to the \"case\" keyword","text":"

The case construct understands two new action list terminators:

The ;& terminator causes execution to continue with the next action list (rather than terminate the case construct).

The ;;& terminator causes the case construct to test the next given pattern instead of terminating the whole execution.

See case

"},{"location":"bash4/#changes-to-the-declare-builtin","title":"Changes to the \"declare\" builtin","text":"

The -p option now prints all attributes and values of declared variables (or functions, when used with -f). The output is fully re-usable as input.

The new option -l declares a variable in a way that the content is converted to lowercase on assignment. For uppercase, the same applies to -u. The option -c causes the content to be capitalized before assignment.

declare -A declares associative arrays (see below).

"},{"location":"bash4/#changes-to-the-read-builtin","title":"Changes to the \"read\" builtin","text":"

The read builtin command has some interesting new features.

The -t option to specify a timeout value has been slightly tuned. It now accepts fractional values and the special value 0 (zero). When -t 0 is specified, read immediately returns with an exit status indicating if there's data waiting or not. However, when a timeout is given, and the read builtin times out, any partial data recieved up to the timeout is stored in the given variable, rather than lost. When a timeout is hit, read exits with a code greater than 128.

A new option, -i, was introduced to be able to preload the input buffer with some text (when Readline is used, with -e). The user is able to change the text, or press return to accept it.

See read

"},{"location":"bash4/#changes-to-the-help-builtin","title":"Changes to the \"help\" builtin","text":"

The builtin itself didn't change much, but the data displayed is more structured now. The help texts are in a better format, much easier to read.

There are two new options: -d displays the summary of a help text, -m displays a manpage-like format.

"},{"location":"bash4/#changes-to-the-ulimit-builtin","title":"Changes to the \"ulimit\" builtin","text":"

Besides the use of the 512 bytes blocksize everywhere in POSIX mode, ulimit supports two new limits: -b for max socket buffer size and -T for max number of threads.

"},{"location":"bash4/#expansions","title":"Expansions","text":""},{"location":"bash4/#brace-expansion","title":"Brace Expansion","text":"

The brace expansion was tuned to provide expansion results with leading zeros when requesting a row of numbers.

See brace

"},{"location":"bash4/#parameter-expansion","title":"Parameter Expansion","text":"

Methods to modify the case on expansion time have been added.

On expansion time you can modify the syntax by adding operators to the parameter name.

See Case modification on parameter expansion

"},{"location":"bash4/#substring-expansion","title":"Substring expansion","text":"

When using substring expansion on the positional parameters, a starting index of 0 now causes \\$0 to be prepended to the list (if the positional parameters are used). Before, this expansion started with \\$1:

# this should display $0 on Bash v4, $1 on Bash v3\necho ${@:0:1}\n
"},{"location":"bash4/#globbing","title":"Globbing","text":"

There's a new shell option globstar. When enabled, Bash will perform recursive globbing on ** \u2013 this means it matches all directories and files from the current position in the filesystem, rather than only the current level.

The new shell option dirspell enables spelling corrections on directory names during globbing.

See globs

"},{"location":"bash4/#associative-arrays","title":"Associative Arrays","text":"

Besides the classic method of integer indexed arrays, Bash 4 supports associative arrays.

An associative array is an array indexed by an arbitrary string, something like

declare -A ASSOC\n\nASSOC[First]=\"first element\"\nASSOC[Hello]=\"second element\"\nASSOC[Peter Pan]=\"A weird guy\"\n

See arrays

"},{"location":"bash4/#redirection","title":"Redirection","text":"

There is a new &>> redirection operator, which appends the standard output and standard error to the named file. This is the same as the good old >>FILE 2>&1 notation.

The parser now understands |& as a synonym for 2>&1 |, which redirects the standard error for a command through a pipe.

See redirection

"},{"location":"bash4/#interesting-new-shell-variables","title":"Interesting new shell variables","text":"Variable Description BASHPID contains the PID of the current shell (this is different than what $$ does!) PROMPT_DIRTRIM specifies the max. level of unshortened pathname elements in the prompt FUNCNEST control the maximum number of shell function recursions

See shellvars

"},{"location":"bash4/#interesting-new-shell-options","title":"Interesting new Shell Options","text":"

The mentioned shell options are off by default unless otherwise mentioned.

Option Description checkjobs check for and report any running jobs at shell exit compat* set compatiblity modes for older shell versions (influences regular expression matching in [[ ... ]] dirspell enables spelling corrections on directory names during globbing globstar enables recursive globbing with ** lastpipe (4.2) to execute the last command in a pipeline in the current environment

See shell_options

"},{"location":"bash4/#misc","title":"Misc","text":""},{"location":"commands/classictest/","title":"The classic test command","text":"

test <EXPRESSION>

[ <EXPRESSION> ]

"},{"location":"commands/classictest/#general-syntax","title":"General syntax","text":"

This command allows you to do various tests and sets its exit code to 0 (true) or 1 (false) whenever such a test succeeds or not. Using this exit code, it's possible to let Bash react on the result of such a test, here by using the command in an if-statement:

#!/bin/bash\n\n# test if /etc/passwd exists\nif test -e /etc/passwd; then\n  echo \"Alright man...\" >&2\nelse\n  echo \"Yuck! Where is it??\" >&2\n  exit 1\nfi\n

The syntax of the test command is relatively easy. Usually it's the command name test followed by a test type (here -e for \"file exists\") followed by test-type-specific values (here the filename to check, /etc/passwd).

There's a second standardized command that does exactly the same: the command [ \u2013 the difference just is that it's called [ and the last argument to the command must be a ]: It forms [ <EXPRESSION> ].

Let's rewrite the above example to use it:

#!/bin/bash\n\n# test if /etc/passwd exists\nif [ -e /etc/passwd ]; then\n  echo \"Alright man...\" >&2\nelse\n  echo \"Yuck! Where is it??\" >&2\n  exit 1\nfi\n

One might think now that these [ and ] belong to the syntax of Bash's if-clause: No they don't! It's a simple, ordinary command, still!

Another thing you have to remember is that if the test command wants one parameter for a test, you have to give it one parameter. Let's check for some of your music files:

#!/bin/bash\n\nmymusic=\"/data/music/Van Halen/Van Halen - Right Now.mp3\"\n\nif [ -e \"$mymusic\" ]; then\n  echo \"Let's rock\" >&2\nelse\n  echo \"No music today, sorry...\" >&2\n  exit 1\nfi\n

As you definitely noted, the filename contains spaces. Since we call a normal ordinary command (test or [) the shell will word-split the expansion of the variable mymusic: You need to quote it when you don't want the test-command to complain about too many arguments for this test-type! If you didn't understand it, please read the article about words....

Please also note that the file-tests want one filename to test. Don't give a glob (filename-wildcards) as it can expand to many filenames => too many arguments!

Another common mistake is to provide too few arguments:

[ \"$mystring\"!=\"test\" ]\n

This provides exactly one test-argument to the command. With one parameter, it defaults to the -n test: It tests if a provided string is empty (FALSE) or not (TRUE) - due to the lack of spaces to separate the arguments the shown command always ends TRUE!

Well, I addressed several basic rules, now let's see what the test-command can do for you. The Bash test-types can be split into several sections: file tests, string tests, arithmetic tests, misc tests. Below, the tests marked with are non-standard tests (i.e. not in SUS/POSIX/etc..).

"},{"location":"commands/classictest/#file-tests","title":"File tests","text":"

This section probably holds the most tests, I'll list them in some logical order. Since Bash 4.1, all tests related to permissions respect ACLs, if the underlying filesystem/OS supports them.

Operator syntax Description -a True if exists. (not recommended, may collide with -a for AND, see below) -e True if exists. -f True, if exists and is a regular file. -d True, if exists and is a directory. -c True, if exists and is a character special file. -b True, if exists and is a block special file. -p True, if exists and is a named pipe (FIFO). -S True, if exists and is a socket file. -L True, if exists and is a symbolic link. -h True, if exists and is a symbolic link. -g True, if exists and has sgid bit set. -u True, if exists and has suid bit set. -r True, if exists and is readable. -w True, if exists and is writable. -x True, if exists and is executable. -s True, if exists and has size bigger than 0 (not empty). -t True, if file descriptor is open and refers to a terminal. -nt True, if is newer than (mtime). -ot True, if is older than (mtime). -ef True, if and refer to the same device and inode numbers."},{"location":"commands/classictest/#string-tests","title":"String tests","text":"Operator syntax Description -z True, if is empty. -n True, if is not empty (this is the default operation). = True, if the strings are equal. != True, if the strings are not equal. < True if sorts before lexicographically (pure ASCII, not current locale!). Remember to escape! Use < > True if sorts after lexicographically (pure ASCII, not current locale!). Remember to escape! Use >"},{"location":"commands/classictest/#arithmetic-tests","title":"Arithmetic tests","text":"Operator syntax Description -eq True, if the integers are equal. -ne True, if the integers are NOT equal. -le True, if the first integer is less than or equal second one. -ge True, if the first integer is greater than or equal second one. -lt True, if the first integer is less than second one. -gt True, if the first integer is greater than second one."},{"location":"commands/classictest/#misc-syntax","title":"Misc syntax","text":"Operator syntax Description -a True, if and are true (AND). Note that -a also may be used as a file test (see above) -o True, if either or is true (OR). ! True, if is false (NOT). ( ) Group a test (for precedence). Attention: In normal shell-usage, the ( and ) must be escaped; use ( and )! -o True, if the shell option is set. -v True if the variable has been set. Use var[n] for array elements. -R True if the variable has been set and is a nameref variable (since 4.3-alpha)"},{"location":"commands/classictest/#number-of-arguments-rules","title":"Number of Arguments Rules","text":"

The test builtin, especially hidden under its [ name, may seem simple but is in fact causing a lot of trouble sometimes. One of the difficulty is that the behaviour of test not only depends on its arguments but also on the number of its arguments.

Here are the rules taken from the manual:

Note

This is for the command test, for [ the number of arguments is calculated without the final ], for example [ ] follows the \"zero arguments\" rule.

These rules may seem complex, but it's not so bad in practice. Knowing them might help you to explain some of the \"unexplicable\" behaviours you might encounter:

var=\"\"\nif [ -n $var ]; then echo \"var is not empty\"; fi\n

This code prints \"var is not empty\", even though -n something is supposed to be true if $var is not empty - why?

Here, as $var is not quoted, word splitting occurs and $var results in actually nothing (Bash removes it from the command's argument list!). So the test is in fact [ -n ] and falls into the \"one argument\" rule, the only argument is \"-n\" which is not null and so the test returns true. The solution, as usual, is to quote the parameter expansion: [ -n \"$var\" ] so that the test has always 2 arguments, even if the second one is the null string.

These rules also explain why, for instance, -a and -o can have several meanings.

"},{"location":"commands/classictest/#and-and-or","title":"AND and OR","text":""},{"location":"commands/classictest/#the-prefered-way","title":"The Prefered Way","text":"

The way often recommended to logically connect several tests with AND and OR is to use several single test commands and to combine them with the shell && and || list control operators.

See this:

if [ -n \"$var\"] && [ -e \"$var\"]; then\n    echo \"\\$var is not null and a file named $var exists!\"\nfi\n

The return status of AND and OR lists is the exit status of the last command executed in the list

"},{"location":"commands/classictest/#the-other-way-a-and-o","title":"The other way: -a and -o","text":"

The logical operators AND and OR for the test-command itself are -a and -o, thus:

if [ -n \"$var\" -a -e \"$var\" ] ; then\n    echo \"\\$var is not null and a file named $var exists\"\nfi\n

They are not && or ||:

$ if [ -n \"/tmp\" && -d \"/tmp\"]; then echo true; fi # DOES NOT WORK\nbash: [: missing `]'\n

You might find the error message confusing, [ does not find the required final ], because as seen above && is used to write a list of commands. The if statement actually sees two commands:

...which must fail.

"},{"location":"commands/classictest/#why-you-should-avoid-using-a-and-o","title":"Why you should avoid using -a and -o","text":""},{"location":"commands/classictest/#if-portability-is-a-concern","title":"If portability is a concern","text":"

POSIX\u00ae/SUSv3 does not specify the behaviour of test in cases where there are more than 4 arguments. If you write a script that might not be executed by Bash, the behaviour might be different! 1

"},{"location":"commands/classictest/#if-you-want-the-cut-behaviour","title":"If you want the cut behaviour","text":"

Let's say, we want to check the following two things (AND):

  1. if a string is null (empty)
  2. if a command produced an output

Let's see:

if [ -z \"false\" -a -z \"$(echo I am executed >&2)\" ] ; then ... \n

=> The arguments are all expanded before test runs, thus the echo-command is executed.

if [ -z \"false\" ] && [ -z \"$(echo I am not executed >&2)\" ]; then... \n

=> Due to the nature of the && list operator, the second test-command runs only if the first test-command returns true, our echo-command is not executed.

Note

In my opinion, -a and -o are also less readable [pgas]

"},{"location":"commands/classictest/#precedence-and-parenthesis","title":"Precedence and Parenthesis","text":"

Take care if you convert your scripts from using -a and -o to use the list way (&& and ||):

That means, you can get different results, depending on the manner of use:

$ if [ \"true\" ] || [ -e /does/not/exist ] && [ -e /does/not/exist ]; then echo true; else echo false; fi\nfalse\n\n$ if [ \"true\" -o -e /does/not/exist -a -e /does/not/exist ]; then  echo true; else echo false;fi\ntrue\n

As a result you have to think about it a little or add precedence control (parenthesis).

For && and || parenthesis means (shell-ly) grouping the commands, and since ( ... ) introduces a subshell we will use { ... } instead:

$ if  [ \"true\" ] || { [ -e /does/not/exist ]  && [ -e /does/not/exist ] ;} ; then echo true; else echo false; fi\ntrue\n

For the test command, the precedence parenthesis are, as well, ( ), but you need to escape or quote them, so that the shell doesn't try to interpret them:

$ if [ ( \"true\" -o -e /does/not/exist ) -a -e /does/not/exist ]; then  echo true; else echo false; fi\nfalse\n\n# equivalent, but less readable IMHO:\n$ if [ '(' \"true\" -o -e /does/not/exist ')' -a -e /does/not/exist ]; then  echo true; else echo false; fi\nfalse\n
"},{"location":"commands/classictest/#not","title":"NOT","text":"

As for AND and OR, there are 2 ways to negate a test with the shell keyword ! or passing ! as an argument to test.

Here ! negates the exit status of the command test which is 0 (true), and the else part is executed:

if ! [ -d '/tmp' ]; then echo \"/tmp doesn't exists\"; else echo \"/tmp exists\"; fi\n

Here the test command itself exits with status 1 (false) and the else is also executed:

if  [ ! -d '/tmp' ]; then echo \"/tmp doesn't exists\"; else echo \"/tmp exists\"; fi\n

Unlike for AND and OR, both methods for NOT have an identical behaviour, at least for doing one single test.

"},{"location":"commands/classictest/#pitfalls-summarized","title":"Pitfalls summarized","text":"

In this section you will get all the mentioned (and maybe more) possible pitfalls and problems in a summary.

"},{"location":"commands/classictest/#general","title":"General","text":"

Here's the copy of a mail on bug-bash list. A user asking a question about using the test command in Bash, he's talking about a problem, which you may have already had yourself:

From: (PROTECTED)\nSubject: -d option not working. . .?\nDate: Tue, 11 Sep 2007 21:51:59 -0400\nTo: bug-bash@gnu.org\n\nHi All,\n\nI've got a script that I'm trying to set up, but it keeps telling me  \nthat  \"[-d command not found\".  Can someone please explain what is  \nwrong with this?:\n\n\n\n\n#!/bin/sh\n\nfor i in $*\ndo\n{\n    if  [-d $i]\n    then\n        echo \"$i is a directory! Yay!\"\n    else\n        echo \"$i is not a directory!\"\n    fi\n}\ndone\n\nRegards\n

See the problem regarding the used test-command (the other potential problems are not of interest here)?

[-d $i]\n

He simply didn't know that test or [ is a normal, simple command. Well, here's the answer he got. I quote it here, because it's a well written text that addresses most of the common issues with the \"classic\" test command:

From: Bob Proulx (EMAIL PROTECTED)\nSubject: Re: -d option not working. . .?\nDate: Wed, 12 Sep 2007 10:32:35 -0600\nTo: bug-bash@gnu.org\n\n> (QUOTED TEXT WAS REMOVED)\n\nThe shell is first and foremost a way to launch other commands.  The\nsyntax is simply \"if\" followed by a command-list, (e.g. if /some/foo;\nor even if cmd1; cmd2; cmd3; then).  Plus the '( ... )' syntax is\nalready taken by the use of starting a subshell.\n\nAs I recall in the original shell language the file test operator was\nnot built-in.  It was provided by the standalone '/bin/test' command.\nThe result was effectively this:\n\n  if /bin/test -d somedir\n\nAlthough the full path /bin/test was never used.  I showed it that way\nhere for emphasis that following the 'if' statement is a command list.\nNormally it would simply have been:\n\n  if test -d somedir\n\nOf course that is fine and for the best portability that style is\nstill the recommended way today to use the test command.  But many\npeople find that it looks different from other programming languages.\nTo make the test operator (note I mention the test operator and not\nthe shell language, this is a localized change not affecting the\nlanguage as a whole) look more like other programming languages the\n'test' program was coded to ignore the last argument if it was a ']'.\nThen a copy of the test program could be used as the '[' program.\n\n  ...modify /bin/test to ignore ']' as last argument...\n  cp /bin/test /bin/[\n\nThis allows:\n\n  if [ -d somedir ]\n\nDoesn't that look more normal?  People liked it and it caught on.  It\nwas so popular that both 'test' and '[' are now shell built-ins.  They\ndon't launch an external '/bin/test' program anymore.  But they *used*\nto launch external programs.  Therefore argument parsing is the same\nas if they still did launch an external program.  This affects\nargument parsing.\n\n  it test -f *.txt\n  test: too many arguments\n\nOops.  I have twenty .txt files and so test got one -f followed by the\nfirst file followed by the remaining files.  (e.g. test -f 1.txt 2.txt\n3.txt 4.txt)\n\n  if test -d $file\n  test: argument expected\n\nOops.  I meant to set file.\n\n  file=/path/some/file\n  if test -d $file\n\nIf variables such as that are not set then they wlll be expanded by\nthe shell before passing them to the (possibly external) command and\ndisappear entirely.  This is why test arguments should always be quoted.\n\n  if test -d \"$file\"\n  if [ -d \"$file\" ]\n\nActually today test is defined that if only one argument is given as\nin this case \"test FOO\" then then test returns true if the argument is\nnon-zero in text length.  Because \"-d\" is non-zero length \"test -d\" is\ntrue.  The number of arguments affects how test parses the args.  This\navoids a case where depending upon the data may look like a test\noperator.\n\n  DATA=\"something\"\n  if test \"$DATA\"         # true, $DATA is non-zero length\n\n  DATA=\"\"\n  if test \"$DATA\"         # false, $DATA is zero length\n\nBut the problem case is how should test handle an argument that looks\nlike an operator?  This used to generate errors but now because it is\nonly one argument is defined to be the same as test -n $DATA.\n\n  DATA=\"-d\"\n  if test \"$DATA\"         # true, $DATA is non-zero length\n  if test -d              # true, same as previous case.\n\nBecause test and [ are possibly external commands all of the parts of\nthem are chosen to avoid shell metacharacters.  The Fortran operator\nnaming was well known at the time (e.g. .gt., .eq., etc.) and was\npressed into service for the shell test operator too.  Comming from\nFortran using -gt, -eq, etc. looked very normal.\n\nIncorrect use generating unlikely to be intended results:\n\n  if test 5 > 2    # true, \"5\" is non-zero length, creates file named \"2\"\n\nIntended use:\n\n  if test 5 -gt 2  # true (and no shell meta characters needing quoting)\n\nThen much later, sometime in the mid 1980's, the Korn sh decided to\nimprove upon this situation.  A new test operator was introduced.\nThis one was always a shell built-in and therefore could act upon the\nshell arguments directly.  This is '[[' which is a shell keyword.\n(Keyword, metacharacters, builtins, all are different.)  Because the\nshell processes [[ internally all arguments are known and do not need\nto be quoted.\n\n  if [[ -d $file ]]  # okay\n  if [[ 5 > 2 ]]     # okay\n\nI am sure that I am remembering a detail wrong but hopefully this is\nuseful as a gentle introduction and interesting anyway.\n\nBob\n

I hope this text protects you a bit from stepping from one pitfall into the next.

I find it very interesting and informative, that's why I quoted it here. Many thanks, Bob, also for the permission to copy the text here!

"},{"location":"commands/classictest/#code-examples","title":"Code examples","text":""},{"location":"commands/classictest/#snipplets","title":"Snipplets","text":"

Some code snipplets follow, different ways of shell reaction is used.

"},{"location":"commands/classictest/#listing-directories","title":"Listing directories","text":"

Using a for-loop to iterate through all entries of a directory, if an entry is a directory ([ -d \"$fn\" ]), print its name:

for fn in *; do\n  [ -d \"$fn\" ] && echo \"$fn\"\ndone\n
"},{"location":"commands/classictest/#see-also","title":"See also","text":"
  1. Of course, one can wonder what is the use of including the parenthesis in the specification without defining the behaviour with more than 4 arguments or how usefull are the examples with 7 or 9 arguments attached to the specification. \u21a9

"},{"location":"commands/builtin/caller/","title":"The caller builtin command","text":""},{"location":"commands/builtin/caller/#synopsis","title":"Synopsis","text":"
caller [FRAMENUMBER]\n
"},{"location":"commands/builtin/caller/#description","title":"Description","text":"

The caller builtin command is used to print execution frames of subroutine calls. Without giving a framenumber, the topmost execution frame information is printed (\"who called me\") wile linenumber and filename.

When an execution frame number is given (0 - topmost), the linenumber, the subroutine (function) and the filename is printed. When an invalid execution frame number is given, it exists FALSE. This way it can be used in a loop (see the examples section below).

"},{"location":"commands/builtin/caller/#examples","title":"Examples","text":""},{"location":"commands/builtin/caller/#simple-stack-trace","title":"Simple stack trace","text":"

The code below defines a function die that is used to exit the program. It prints a list of execution frames, starting with the topmost frame (0). The topmost frame is the \"caller of the die function\", in this case function \"f1\".

This way, you can print a \"stack trace\" for debugging or logging purposes.

The code is made very simple, just to show the basic purposes.

#!/bin/bash\n\ndie() {\n  local frame=0\n  while caller $frame; do\n    ((++frame));\n  done\n  echo \"$*\"\n  exit 1\n}\n\nf1() { die \"*** an error occured ***\"; }\nf2() { f1; }\nf3() { f2; }\n\nf3\n

Output

12 f1 ./callertest.sh\n13 f2 ./callertest.sh\n14 f3 ./callertest.sh\n16 main ./callertest.sh\n*** an error occured ***\n
"},{"location":"commands/builtin/caller/#notes","title":"Notes","text":""},{"location":"commands/builtin/caller/#portability-considerations","title":"Portability considerations","text":""},{"location":"commands/builtin/caller/#see-also","title":"See also","text":""},{"location":"commands/builtin/cd/","title":"The cd builtin command","text":""},{"location":"commands/builtin/cd/#synopsis","title":"Synopsis","text":"
cd [-L|-P] [DIRECTORY]\n\ncd -\n
"},{"location":"commands/builtin/cd/#description","title":"Description","text":"

The cd builtin command is used to change the current working directory

The cd builtin command searches the directories listed in CDPATH for a matching directory.

The default behaviour is to follow symbolic links unless the -P option is given or the shell is configured to do so (see the -P option of the set builtin command).

"},{"location":"commands/builtin/cd/#options","title":"Options","text":"Option Description -L Follow symbolic links (default) -P Do not follow symbolic links -@ Browse a file's extended attributed, if supported"},{"location":"commands/builtin/cd/#exit-status","title":"Exit status","text":""},{"location":"commands/builtin/cd/#examples","title":"Examples","text":""},{"location":"commands/builtin/cd/#change-the-working-directory-to-the-users-home-directory","title":"Change the working directory to the user's home directory","text":"
cd\n
"},{"location":"commands/builtin/cd/#change-the-working-directory-to-the-previous-directory","title":"Change the working directory to the previous directory","text":"
cd -\n
"},{"location":"commands/builtin/cd/#portability-considerations","title":"Portability considerations","text":""},{"location":"commands/builtin/cd/#see-also","title":"See also","text":""},{"location":"commands/builtin/declare/","title":"The declare builtin command","text":""},{"location":"commands/builtin/declare/#synopsis","title":"Synopsis","text":"
declare [-aAfFgilnrtux] [-p] [NAME[=VALUE] ...]\n\n# obsolete typeset synonym\ntypeset [-aAfFgilnrtux] [-p] [NAME[=VALUE] ...]\n
"},{"location":"commands/builtin/declare/#description","title":"Description","text":"

declare is used to display or set variables along with variable attributes. When used to display variables/functions and their value, the output is re-usable as input for the shell.

If no NAME is given, it displays the values of all variables or functions when restricted by the -f option.

If NAME is followed by =VALUE, declare also sets the value for a variable.

When used in a function, declare makes NAMEs local variables, unless used with the -g option.

Don't use it's synonym typeset when coding for Bash, since it's tagged as obsolete.

"},{"location":"commands/builtin/declare/#options","title":"Options","text":"

Below, [-+]X indicates an attribute, use -X to set the attribute, +X to remove it.

Option Description [-+]a make NAMEs indexed arrays (removing with +a is valid syntax, but leads to an error message) [-+]A make NAMEs associative arrays [-+]c Undocumented convert NAMEs to \"capcase\" on assignment (makes the first letter upper-case and the rest lower). Requires Bash built with -DCASEMOD_CAPCASE -f restrict action or display to function names and definitions (removing with +f is valid syntax, but leads to an error message) -F restrict display to function names only (plus line number and source file when debugging) -g create global variables when used in a shell function; otherwise ignored (by default, declare declares local scope variables when used in shell functions) [-+]i make NAMEs have the \"integer\" attribute [-+]l convert NAMEs to lower case on assignment (makes sure the variable contains only lower case letters) [-+]n make NAME a reference to the variable named by its value. Introduced in Bash 4.3-alpha. ''${!NAME}'' reveals the reference variable name, VALUE. Use unset -n NAME to unset the variable. (unset -v NAME unsets the VALUE variable.) Use [[ -R NAME ]] to test if NAME has been set to a VALUE, another variable's name. -p display the attributes and value of each NAME [-+]r make NAMEs readonly (removing with +r is valid syntax, but not possible) [-+]t make NAMEs have the \"trace\" attribute (effective only for functions) [-+]u convert NAMEs to upper case on assignment (makes sure the variable contains only upper case letters) [-+]x make NAMEs exported"},{"location":"commands/builtin/declare/#return-status","title":"Return status","text":"Status Reason 0 no error != 0 invalid option != 0 invalid variable name given != 0 attempt to define a function using -f != 0 assignment to a readonly variable != 0 removing the readonly-attribute from a readonly variable != 0 assignment to an array variable without the compound assignment syntax (array=(...)) != 0 attempt to use +a to \"destroy\" an array != 0 attemt to display a non-existent function with -f"},{"location":"commands/builtin/declare/#notes","title":"Notes","text":"

Unix shells offer very few datatypes. Bash and some other shells extend this by allowing \"attributes\" to be set on variable names. The only attributes specified by POSIX are export and readonly, which are set by their own dedicated builtins. Datatypes in bash have a few other interesting capabilities such as the ability to modify data on assignment.

"},{"location":"commands/builtin/declare/#examples","title":"Examples","text":""},{"location":"commands/builtin/declare/#display-defined-functions","title":"Display defined functions","text":"

declare -f can be used to display all defined functions...

$ declare -f\nfoo ()\n{\n    echo \"FOO is BAR\"\n}\nworld ()\n{\n    echo \"Hello World!\"\n}\n

...or just a specific defined function.

$ declare -f foo\nfoo ()\n{\n    echo \"FOO is BAR\"\n}\n
"},{"location":"commands/builtin/declare/#nameref","title":"Nameref","text":"

Bash 4.3 adds a new way to indirectly reference variables. typeset -n or declare -n can be used to make a variable indirectly refer to another. In Bash, the lvalue of the assignment given to typeset -n or declare -n will refer to the variable whose name is expanded on the RHS.

typeset -n is used in the example below. See notes below.

# Sum a set of arrays and assign the result indirectly, also printing each intermediary result (without portability workarounds)\n# sum name arrname [ arrname ... ]\nfunction sum {\n    typeset -n _result=$1 _arr\n    typeset IFS=+\n    _result=0\n    for _arr in \"${@:2}\"; do                        # Demonstrate the special property of \"for\" on a nameref.\n        (( _result += ${_arr[*]} ))\n        printf '%s = %d\\n' \"${!_result}\" \"$_result\" # Demonstrate the special property of ${!ref} on a nameref.\n    done\n}\n\na=(1 2 3) b=(6 5 4) c=(2 4 6)\nsum total a b c\nprintf 'Final value of \"total\" is: %d\\n' \"$total\"\n
function sum { typeset -n _result=$1 shift typeset IFS=+ _arrx _result=0 for _arrx in \"$@\"; do # Demonstrate the special property of \"for\" on a nameref. typeset -n _arr=$_arrx (( _result += ${_arr[*]} )) printf '%s = %d\\n' \"${!_result}\" \"$_result\" # Demonstrate the special property of ${!ref} on a nameref. done } a=(1 2 3); b=(6 5 4); c=(2 4 6) sum total a b c printf \\'Final value of \\\"total\\\" is: %d\\\\n\\' \\\"\\$total\\\"

typeset -n is currently implemented in ksh93, mksh, and Bash 4.3. Bash and mksh's implementations are quite similar, but much different from ksh93's. See Portability considerations for details. ksh93 namerefs are much more powerful than Bash's.

"},{"location":"commands/builtin/declare/#portability-considerations","title":"Portability considerations","text":""},{"location":"commands/builtin/declare/#see-also","title":"See also","text":""},{"location":"commands/builtin/echo/","title":"The echo builtin command","text":""},{"location":"commands/builtin/echo/#synopsis","title":"Synopsis","text":"
echo [-neE] [arg ...]\n
"},{"location":"commands/builtin/echo/#description","title":"Description","text":"

echo outputs it's args to stdout, separated by spaces, followed by a newline. The return status is always 0. If the shopt option xpg_echo is set, Bash dynamically determines whether echo should expand escape characters (listed below) by default based on the current platform. echo doesn't interpret -- as the end of options, and will simply print this string if given.

"},{"location":"commands/builtin/echo/#options","title":"Options","text":"Option Description -n The trailing newline is suppressed. -e Interpretation of the following backslash-escaped characters (below) is enabled. -E Disables the interpretation of these escape characters, even on systems where they are interpreted by default."},{"location":"commands/builtin/echo/#escape-sequences","title":"Escape sequences","text":"Escape Description \\a alert (bell) \\b backspace \\c suppress further output \\e \\E an escape character \\f form feed \\n new line \\r carriage return \\t horizontal tab \\v vertical tab \\\\ backslash \\0nnn the eight-bit character whose value is the octal value nnn (zero to three octal digits) \\xHH the eight-bit character whose value is the hexadecimal value HH (one or two hex digits) \\uHHHH the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value HHHH (one to four hex digits) \\UHHHHHHHH the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value HHHHHHHH (one to eight hex digits)"},{"location":"commands/builtin/echo/#examples","title":"Examples","text":""},{"location":"commands/builtin/echo/#portability-considerations","title":"Portability considerations","text":""},{"location":"commands/builtin/echo/#see-also","title":"See also","text":""},{"location":"commands/builtin/eval/","title":"The eval builtin command","text":""},{"location":"commands/builtin/eval/#synopsis","title":"Synopsis","text":"
eval: eval [arg ...]\n
"},{"location":"commands/builtin/eval/#description","title":"Description","text":"

eval takes its arguments, concatenates them separated by spaces, and executes the resulting string as Bash code in the current execution environment. eval in Bash works in essentially the same way as most other languages that have an eval function. Perhaps the easiest way to think about eval is that it works in the same way as running \\'\\'bash -c \\\"bash code...\\\" \\'\\'from a script, except in the case of eval, the given code is executed in the current shell environment rather than a child process.

"},{"location":"commands/builtin/eval/#examples","title":"Examples","text":"

In this example, the literal text within the here-document is executed as Bash code exactly as though it were to appear within the script in place of the eval command below it.

#!/usr/bin/env bash\n{ myCode=$(</dev/stdin); } <<\\EOF\n... arbitrary bash code here ...\nEOF\n\neval \"$myCode\"\n
"},{"location":"commands/builtin/eval/#expansion-side-effects","title":"Expansion side-effects","text":"

Frequently, eval is used to cause side-effects by performing a pass of expansion on the code before executing the resulting string. This allows for things that otherwise wouldn't be possible with ordinary Bash syntax. This also, of course, makes eval the most powerful command in all of shell programming (and in most other languages for that matter).

This code defines a set of identical functions using the supplied names. eval is the only way to achieve this effect.

main() {\n    local fun='() { echo \"$FUNCNAME\"; }' x\n\n    for x in {f..n}; do\n        eval \"${x}${fun}\"\n    done\n\n    \"$@\"\n}\n\nmain \"$@\"\n
"},{"location":"commands/builtin/eval/#using-printf-q","title":"Using printf %q","text":"

The printf %q format string performs shell escaping on its arguments. This makes printf %q the \"anti-eval\" - with each pass of a string through printf requiring another eval to peel off the escaping again.

while (( ++n <= 5 )) || ! evalBall=\"eval $evalBall\"; do\n    printf -v evalBall 'eval %q' \"printf $n;${evalBall-printf '0\\n'}\"\ndone\n$evalBall\n

The above example is mostly fun and games but illustrates the printf %q property.

"},{"location":"commands/builtin/eval/#higher-order-functions","title":"Higher-order functions","text":"

Since all current POSIX-compatible shells lack support for first-class functions, it can be tempting and sometimes useful to simulate some of their effect using eval to evaluate a string containing code.

This example shows partial application using eval.

function partial {\n    eval shift 2 \\; function \"$1\" \\{ \"$2\" \"$(printf '%q ' \"${@:3}\")\" '\"$@\"; }'\n}\n\nfunction repeat {\n    [[ $1 == +([0-9]) ]] || return\n    typeset n\n    while ((n++ < $1)); do\n        \"${@:2}\"\n    done\n}\n\npartial print3 repeat 3 printf '%s ' # Create a new function named print3\nprint3 hi                            # Print \"hi\" 3 times\necho\n

This is very easy to do incorrectly and not usually considered idiomatic of Bash if used extensively. However abstracting eval behind functions that validate their input and/or make clear which input must be controlled carefully by the caller is a good way to use it.

"},{"location":"commands/builtin/eval/#portability-considerations","title":"Portability considerations","text":"