Bash constructs

{ code; }   Command block

(code)   Subshell

$'string'   Quoting

${!var}   Indirect Variable Reference

"'$var" | '"string'   Char to Octal/Decimal/Hex

{ code; } - command block

(code) - subshell

Variable Subsitution

Variable substitution is generally characterized by using curly braces of the form ${var...}. There is an additional form ${#...} used for determining a number.

If var is followed by one or two forward slashes ${var/...} then the substitution is of the form /pattern/replacement or /pattern drop if no /replacement given.

If var is followed by one or two octothorps ${var#...} then the substitution is of the the form #pattern drop where pattern occurs at the beginning.

If var is followed by one or two percent signs ${var%...} then the substitution is of the form %pattern drop where pattern occurs at the end.

If var is followed by a slash and then an octothorpe ${var/#...} then the substitution is of the form /#pattern drop where a greedy match is formed at the beginning.

If var is followed by a slash and then a percent sign ${var/%...} then the substitution is of the form /%pattern drop where a greedy match is formed at the end.

If the pattern is followed by /repl then a replacement is made where the matched pattern was dropped

If var is followed by a colon ${var:...} then any of the chars - = ? or + then the substitution is of the form where either var or the value following is used depending on the char following the colon. If one of the chars is used without the colon then var must be nonnull as well as set.

If var is followed by a colon and a digit ${var:n:m} then the substitution is of the form of a substring, starting at position n (0 based) and containing m characters or the remainder of the string if no m is given

For the form ${#...}, there are three constructs: ${#var} length of var, ${#$} and ${#@} number of positional parameters.

For the form ${!...}, there are two constructs which produce the same result: ${!prefix*} and ${!prefix@}. Both list the variables whose names begin with prefix

NOTE: Use the $'\xNN' syntax for non-printing characters.

${a} is the general form for dereferencing. The braces are normally optional, excepting arrays.

Here are the constructs:

  1. ${var/pat} delete first match. Does not work with * wildcard
  2. ${var//pat} delete every match
  3. ${var/pat/repl} replace first match
  4. ${var//pat/repl} replace every match
  5. ${var#pat} delete shortest match from beginning
  6. ${var##pat} delete longest match from beginning
  7. ${var%pat} delete shortest match from end
  8. ${var%%pat} delete longest match from end
  9. ${var/#pat} delete longest match from beginning
  10. ${var/#pat/repl} replace longest match from beginning
  11. ${var/%pat} delete longest match from end
  12. ${var/%pat/repl} replace longest match from end
  13. ${var:-value} use var if set and non-null, else value
  14. ${var-value} use var if set, else value
  15. ${var:=value} use var if set and non-null, else value and assign value to var(not for cl parms)
  16. ${var=value} use var if set, else value and assign value to var
  17. ${var:?} if null or not set, print "parameter null or not set" and exit script
  18. ${var?} if not set, print "parameter null or not set" and exit script
  19. ${var:?value} use var if set and non-null else print value and exit script
  20. ${var?value} use var if set else print value and exit script
  21. ${var:+value} use value if var is set, and non-null else nothing
  22. ${var+value} use value if var is set, else nothing
  23. ${#var} use length of var (number of characters)
  24. ${#*} use number of positional parameters
  25. ${@} same as ${#*}
  26. ${var:pos} starting at position pos extract the rest of the string
  27. ${var:pos:len} starting at position pos extract len characters
  28. ${!prefix*} list the variables whose names begin with prefix
  29. ${!prefix@} list the variables whose names begin with prefix

Note that while ${var%%pat} and ${var/%pat} produce identical results
and that ${var##pat} and ${var/#pat} produce identical results there is no equivalent ${var%%pat/repl} or ${var##pat/repl} so ${var/%pat/repl} and ${var/#pat/repl} must be used to replace the longest match and ${var/pat/repl} must be used to replace the shortest match from the beginning. Note also that the wildcard * is greedy when used with ${var/pat}, ${var/%pat} and there is no way to replace the shortest match from the end using the * wildcard. For example if a=ABCXYZABC and you want to replace the final ABC with 123 then

${a/%A?C/123}

works, producing ABCXYZ123 but

${a/%A*C/123}

produces 123 because of the greedy *. The obvious workaround is to simply chop the final ABC with ${a%A*} and then append the 123

${a%A*}123

Some examples: Assume a='Hello, World!' and b='' and c is unset

  1. ${a/*l} ==> d! (greedy *)
    ${a#*l} ==> lo, World! (work around)
    ${a/??l} ==> lo, World! (? wildcard ok as long as you know how many to use
  2. ${a//o} ==> Hell, Wrld!
    ${a//?l} ==> Hlo, Wod! another bug? el, ll, and rl all match but only el and rl are deleted
  3. ${a/?o/3} ==> Hel3, World!
  4. ${a//?o/4} ==> Hel4, 4rld!
    ${a//*o/4} ==> 4rld! (greedy *)
  5. ${a#*o} ==> , World!
  6. ${a##*o} ==> rld!
  7. ${a%o*} ==> Hello, W
  8. ${a%%o*} ==> Hell
  9. ${a/#*o} ==> rld!
  10. ${a/#*o/x} ==> xrld!
  11. ${a/%o*} ==> Hell
  12. ${a/%o*/x} ==> Hellx
  13. ${b:-x} ==> x
    ${c:-x} ==> x
  14. ${b-x} ==> nul
    ${c-x} ==> x
  15. ${b:=x} ==> x also b contains the value x
    ${c:=x} ==> x also c contains the value x
  16. ${b=x} ==> nul
    ${c=x} ==> x also c contains the value x
  17. ${b:?} ==> prints "parameter null or not set" and, if not interactive, exits
    ${c:?} ==> prints "parameter null or not set" and, if not interactive, exits
  18. ${b?} ==> nul
    ${c?} ==> prints "parameter null or not set" and, if not interactive, exits
  19. ${b:?x} ==> prints bash: b: x
    ${c:?x} ==> prints bash: c: x
  20. ${b?x} ==> nul
    ${c?x} ==> prints bash: c: x
  21. ${b:+x} ==> nothing
    ${c:+x} ==> nothing
  22. ${b+x} ==> x
    ${c+x} ==> nothing
  23. ${#a} ==> 13
  24. ${#*} ==> Number of command line parameters
  25. ${#@} ==> Number of command line parameters
  26. ${a:3} ==> lo, World!
  27. ${a:3:2} ==> lo
  28. ${!P*} ==> PATH PIPESTATUS PPID PS1 PS2 PS4 PWD
  29. ${!D@} ==> DBUS_SESSION_BUS_ADDRESS DEFAULTS_PATH DESKTOP_SESSION DIRSTACK DISPLAY
  30. ${!var} (indirect variable reference)

    bar='Hello, World!'
    foo=bar
    echo ${!foo} # --> Hello, World!
    baz=${!foo}
    echo $baz # --> Hello, World!

    This is a replacement for eval var2=\$$var1

    var1=foo
    foo=bar
    eval var2=\$$var1
    echo $var2 # --> bar

    Each invocation of eval forces a re-evaluation of its arguments.

    a='$b'
    b='$c'
    c=d
    
    echo $a             # $b
                        # First level.
    eval echo $a        # $c
                        # Second level.
    eval eval echo $a   # d
                        # Third level.
    

    A simple use for an indirect variable reference
    a='/etc/crontab'
    ls $a # gives a directory listing of /etc/crontab
    [ -s ${!a} ] && echo "$a exists and is not empty"

    Here we are not testing a variable but instead we are testing what the variable is pointing to

    Positional parameters

    Syntax: set [options] [arg1 arg2 ...]

    Example: set -- -1 -x

    Explanation: -- turns off option processing so $1 is set to -1 and $2 is set to -x

    Example: set -- *

    Explanation: set the postitional parameters to the names of all the files in the current directory

    Example: set --

    Explanation: with no arguments, unset the positional parameters,

    Quoting

    Words of the form $'string' are treated specially. The word expands to string, with backslash-escaped characters replaced as specified by the ANSI C standard. Backslash escape sequences, if present, are decoded as follows:
    \a alert (bell)
    \b backspace
    \e an escape character
    \f form feed
    \n new line
    \r carriage return
    \t horizontal tab
    \v vertical tab
    \\ backslash
    \' single quote
    \nnn the eight-bit character whose value is the octal value nnn (one to three digits)
    \xHH the eight-bit character whose value is the hexadecimal value HH (one or two hex digits)
    \cx a control-x character

    CR=$'\r' sets the variable CR to be a hex 0D (decimal 13)

    LF=$'\n' sets the variable LF to be a hex 0A (decimal 10)

    echo 'cat\ndog'
    catndog

    echo $'cat\ndog'
    cat
    dog

    ( execute in a subshell )

    [ $a = 2 ] || (echo noa && echo xxx)
    [ $a = 2 ] || { echo noa && echo xxx; }




    Feed a block at the top with command output
    (Beware the 2048 byte limit of temp files created by pipes)

    Also be aware that you can't get variables out of this block

    command | while read LINE; do
      echo $LINE
    done
    
    also
    
    command | while read WORD1 WORD2 REST; do
      do something with $WORD1
      do something with $WORD2
      do something with $REST
    done
    



    Feed a block at the bottom with command output

    while read LINE; do
      echo $LINE
    done < <(command)
    

    The space between < and < is required
    and this will not work with #!/bin/sh. use #!/bin/bash

    Another form is useful to have script commands and data in the same file

    while read a;do
      do something with $a
    done << EOL
    data line 1
    data line 2
    EOL



    Feed a block at the top with file output

    As above, you can't get variables out of this block

    cat file | while read LINE; do
      echo $LINE
    done
    

    To get variables:

    cat /etc/passwd | ( IFS=:
    while read lognam pw id gp fname home sh; do
      echo $home \"$fname\"
    done )
    



    Feed a block at the bottom with file output

    while read LINE; do
      echo "$LINE"
    done < /etc/joe/joerc|grep -v "^#"|grep -v '^$'
    

    This example code also ignores comment and blank lines




    Using the line command instead of read

    while LINE=$(/usr/bin/line); do
      echo "$LINE"
    done < /etc/joe/joerc|grep -v "^#"|grep -v '^$'
    




    Using input file descriptors

    exec 3<&0		# Associate stdin with fd3
    exec 0> $INFILE		# Redirect $INFILE to stdin
    while read LINE; do
      echo $LINE
    done
    exec 0<&3	# Restore stdin
    exec 3>&-	# Close fd3
    




    Using output file descriptors

    exec 4<&1	# Associate stdout with fd4
    exec 1> $OUTFILE	# Redirect stdout to $OUTFILE
    while read LINE; do
      echo $LINE
    done < $INFILE
    exec 1<&4	# Restore stdout
    exec 4>&-	# Close fd4
    

    Indirect Expansion

    $ bar=3
    $ foo=bar
    $ echo ${!foo}
    3
    $ eval echo \$$foo
    3
    $ eval a=\$$foo
    $ echo $a
    3

    See also Brace Expansion


    Array Key and Value Expansion

    a=(cat dog hat rat)
    for key in ${!a[*]};do echo $key;done
    0
    1
    2
    3
    for value in ${a[*]};do echo $value;done
    cat
    dog
    hat
    rat
    a=("black cat" "hot dog")
    for value in "${a[@]}";do echo $value;done
    black cat
    hot dog
    for value in "${a[*]}";do echo $value;done
    black cat hot dog


    Command substitution

    Command substitution allows the output of a command to replace the command name. There are two forms:

    $(command)

    `command`

    Bash performs the expansion by executing command and replacing the command substitution with the standard output of the command, with any trailing newlines deleted. Embedded newlines are not deleted, but they may be removed during word splitting. The command substitution $(cat file) can be replaced by the equivalent but faster $(< file).

    If the substitution appears within double quotes, word splitting and filename expansion are not performed on the results.

    echo -e $(cat now)
    Now is the time For all good men To go to the aid Of their country.

    echo -e "$(cat now)"
    Now is the time
    For all good men
    To go to the aid
    Of their country.

    for LINE in "$(cat now)"; do echo -e x${LINE}x;done
    xNow is the time For all good men To go to the aid Of their country.x

    for LINE in $(cat now); do echo -e x${LINE}x;done
    xNowx
    xisx
    xthex
    xtimex
    xForx
    xallx
    xgoodx
    xmenx
    xTox
    xgox
    xtox
    xthex
    xaidx
    xOfx
    xtheirx
    xcountry.x

    Brace Expansion

    echo {a,b}{c,d} --> ac ad bc bd
    echo {a..d}{e,f} --> ae af be bf ce cf de df
    cat {file1,file2,file3} > combined_file # Concatenates the files file1, file2, and file3 into combined_file.
    cp /usr/local/bin/file22.{txt,backup} # Copies "/usr/local/bin/file22.txt" to "/usr/local/bin/file22.backup"
    file1='/bin/sh'
    file2='/etc/crontab'
    file3='/boot/grub/'
    ls $file{1,2,3}	# Lists the directories named by the three variables
    

    See also Indirect Expansion


    Send mail to the Webmaster

    logo This site best viewed with a browser
    Warning: This is a Debian centric site and MAY contain peanuts.
    Many thanks to Debra Lynn and Ian Murdock for making Debian possible
    First created Apr 22, 2008 ~ Last revised December 07, 2011

    Valid XHTML 1.0 Strict Valid CSS!