Post

SHELL Note

[toc]


Shell grammar

Simple Commands

A simple command is an optional sequence of variable assignments followed by blank-separated words and redirections, and terminated by a control operator.

  • The first word specifies the command to be executed, and is passed as argument zero.
  • The remaining words are passed as arguments to the invoked command.
  • The return value of a simple command is its exit status, or 128+n if the command is terminated by signal n.

Pipelines

A pipeline is a sequence of one or more commands separated by one of the control operators | or |&.

  1. If |& is used, the standard error of command1 is connected to command2’s standard input through the pipe; it is shorthand for 2>&1 |.
    • This implicit redirection of the standard error is performed after any redirections specified by the command.

The return status of a pipeline is the exit status of the last command, unless the pipefail option is enabled.

  • If pipefail is enabled, the pipeline’s return status is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands exit successfully.
  • If the reserved word ! precedes a pipeline, the exit status of that pipeline is the logical negation of the exit status as described above.
  • The shell waits for all commands in the pipeline to terminate before returning a value.

Lists

A list is a sequence of one or more pipelines separated by one of the operators ;, &, &&, or ||, and optionally terminated by one of ;, &, or <newline>.

Of these list operators, && and have equal precedence, followed by ; and &, which have equal precedence.

A sequence of one or more newlines may appear in a list instead of a semicolon to delimit commands.

  1. command is terminated by the control operator &, the shell executes the command in the background in a subshell.
    • The shell does not wait for the command to finish
    • the return status is 0.
  2. Commands separated by a ; are executed sequentially;
    • the shell waits for each command to terminate in turn.
    • The return status is the exit status of the last command executed.

AND and OR lists are sequences of one of more pipelines

1
2
3
4
5
6
command1 && command2
# command2 is executed only if command1 returns an exit status of zero.

command1 || command2
# command2 is executed only if command1 returns a non-zero exit status.
# The return status of AND and OR lists is the exit status of the last command executed in the list.

Compound Commands

A compound command is one of the following:

  1. (list)
    • list is executed in a subshell environment.
    • Variable assignments and builtin commands that affect the shell’s environment do not remain in effect after the command completes.
    • The return status is the exit status of list.
  2. { list; }
    • list is executed in the current shell environment.
    • The list must be terminated with a newline or semicolon. This is known as a group command.
    • The return status is the exit status of list.
    • unlike the metacharacters ( and ), { and } are reserved words and must occur where a reserved word is permitted to be recognized. Since they do not cause a word break, they must be separated from list by whitespace or another shell metacharacter.
  3. ((expression))
    • The expression is evaluated according to the rules described below in the section “Arithmetic Evaluation”.
    • If the value of the expression is non-zero, the return status is 0; otherwise the return status is 1.
    • This is exactly equivalent to let "expression".
  4. [[ expression ]]
    • Return a status of 0 or 1 depending on the evaluation of the conditional expression expression.
    • Expressions are composed of the primaries described below under the section “Conditional Expressions.”
    • Word splitting and pathname expansion are not performed on the words between the [[ and ]]; tilde expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution, and quote removal are performed.
    • Conditional operators such as -f must be unquoted to be recognized as primaries.
    • When used with [[, the < and > operators sort lexicographically using the current locale

When the == and != operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below under Pattern Matching. If the shell option nocasematch is enabled, the match is performed without regard to the case of alphabetic characters. The return value is 0 if the string matches (==) or does not match (!=) the pattern, and 1 otherwise. Any part of the pattern may be quoted to force it to be matched as a string.

expression

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
( expression )
# Returns the value of expression.
# This may be used to override the normal precedence of operators.

! expression
# True if expression is false.

expression1 && expression2
# True if both expression1 and expression2 are true.
expression1 || expression2
# True if either expression1 or expression2 is true.
# The && and || operators do not evaluate expression2 if the value of expression1 is sufficient to determine the return value of the entire conditional expression.

for name [ [ in [ word ... ] ] ; ] do list ; done
# The list of words following in is expanded, generating a list of items.
# The variable name is set to each element of this list in turn, and list is executed each time.
# If the in word is omitted, the for command executes list once for each positional parameter that is set (see the "Parameters" section below).
# The return status is the exit status of the last command that executes.
# If the expansion of the items following in results in an empty list, no commands are executed, and the return status is 0.


for (( expr1 ; expr2 ; expr3 )) ; do list ; done
# First, the arithmetic expression expr1 is evaluated.
# The arithmetic expression expr2 is then evaluated repeatedly until it evaluates to zero.
# Each time expr2 evaluates to a non-zero value, list is executed and the arithmetic expression expr3 is evaluated.
# If any expression is omitted, it behaves as if it evaluates to 1.
# The return value is the exit status of the last command in list that is executed, or false if any of the expressions is invalid.

select name [ in word ] ; do list ; done
# The list of words following in is expanded, generating a list of items. The set of expanded words is printed on the standard error, each preceded by a number. If the in word is omitted, the positional parameters are printed.
# The PS3 prompt is then displayed and a line read from the standard input.
# If the line consists of a number corresponding to one of the displayed words, then the value of name is set to that word.
# If the line is empty, the words and prompt are displayed again.
# If EOF is read, the command completes.
# Any other value read causes name to be set to null.
# The line read is saved in the variable REPLY. The list is executed after each selection until a break command is executed.
# The exit status of select is the exit status of the last command executed in list, or zero if no commands were executed.

case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac
# A case command first expands word, and tries to match it against each pattern in turn, using the same matching rules as for pathname expansion. The word is expanded using tilde expansion, parameter and variable expansion, arithmetic substitution, command substitution, process substitution and quote removal. Each pattern examined is expanded using tilde expansion, parameter and variable expansion, arithmetic substitution, command substitution, and process substitution. If the shell option nocasematch is enabled, the match is performed without regard to the case of alphabetic characters. When a match is found, the corresponding list is executed. If the ;; operator is used, no subsequent matches are attempted after the first pattern match. Using ;& in place of ;; causes execution to continue with the list associated with the next set of patterns. Using ;;& in place of ;; causes the shell to test the next pattern list in the statement, if any, and execute any associated list on a successful match. The exit status is zero if no pattern matches. Otherwise, it is the exit status of the last command executed in list.

if list; then list; [ elif list; then list; ] ... [ else list; ] fi
# The if list is executed. If its exit status is zero, the then list is executed. Otherwise, each elif list is executed in turn, and if its exit status is zero, the corresponding then list is executed and the command completes. Otherwise, the else list is executed, if present. The exit status is the exit status of the last command executed, or zero if no condition tested true.

while list-1; do list-2; done until list-1; do list-2; done
# The while command continuously executes the list list-2 as long as the last command in the list list-1 returns an exit status of zero. The until command is identical to the while command, except that the test is negated; list-2 is executed as long as the last command in list-1 returns a non-zero exit status. The exit status of the while and until commands is the exit status of the last command executed in list-2, or zero if none was executed.

Parameters

1
2
3
4
5
6
name=[value]
# A variable assigned by a statement
# If value is not given, the variable is assigned the null string.



Arrays

  • Bash provides one-dimensional indexed and associative array variables. Any variable may be used as an indexed array;
  • There is no maximum limit on the size of an array, nor any requirement that members be indexed or assigned contiguously.
  • -a: Indexed arrays are referenced using integers (including arithmetic expressions) and are zero-based;
  • -A: associative arrays are referenced using arbitrary strings.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# the declare builtin will explicitly declare an array.
declare -a name[subscript]

# An indexed array is created automatically if any variable is assigned to
name[subscript]=value.

# Any element of an array
${name[subscript]}
# If subscript is @ or *, the word expands to all members of name.

# These subscripts differ only when the word appears within double quotes.
# If the word is double-quoted, ${name[*]} expands to a single word with the value of each array member separated by the first character of the IFS special variable, and ${name[@]} expands each element of name to a separate word. When there are no array members, ${name[@]} expands to nothing. If the double-quoted expansion occurs within a word, the expansion of the first parameter is joined with the beginning part of the original word, and the expansion of the last parameter is joined with the last part of the original word. This is analogous to the expansion of the special parameters * and @ (see the section "Special Parameters" above).

# length of array
${#name[subscript]}
# If subscript is * or @, the expansion is the number of elements in the array.
# Referencing an array variable without a subscript is equivalent to referencing the array with a subscript of 0.

# to destroy arrays.
unset name
unset name[subscript]
unset name[*]
unset name[@]
# destroys the array element at index subscript.



expansion

seven kinds of expansion performed:

  • brace expansion,
  • tilde expansion,
  • parameter and variable expansion,
  • command substitution,
  • arithmetic expansion,
  • word splitting,
  • and pathname expansion.
  1. Brace expansion
1
2
3
4
5
6
7
8
9
10
11
12
13
14
a{d,c,b}e
# ade ace abe

mkdir /usr/local/src/bash/{old,new,dist,bugs}
# /usr/local/src/bash/old
# /usr/local/src/bash/new
# /usr/local/src/bash/dist,bugs

chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}}
# /usr/ucb/ex
# /usr/ucb/edit
# ../lib/ex?.?*
# ../lib/how_ex

  1. Command substitution
1
2
3
4
5
6
# allows the output of a command to replace the command name.
$(command)
`command`

$(cat file)
$(< file)
  1. Arithmetic expansion
1
2
3
4
5
6
7
# allows the evaluation of an arithmetic expression and the substitution of the result.

$((expression))

# The old format
$[expression]
# is deprecated and will be removed in upcoming versions of bash.

redirection

stdin stdout stderr redirect

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 0< stdin
# 1> stdout
# 2> stderr

-----------------------------

$ echo hello > hello.txt
$ echo world > hello.txt
# world

$ echo hello > hello.txt
$ echo world >> hello.txt
# hello world
# Appending redirected output

-----------------------------

$ echo hello 1> hello.txt
# hello

$ wrongcommand
# wrongcommand: command not found

$ wrongcommand > error.txt
# error.txt: nothing

$ wrongcommand 2> error.txt
# error.txt: wrongcommand: command not found

-----------------------------

$ ./test.py 1> out.txt
# out.txt: output

$ ./test.py 2>1 1> out.txt
# 1: error
# out.txt: output

$ ./test.py 2>&1 1> out.txt
# file descriptor screen: display error
# out.txt: output

$ ./test.py 1> out.txt 2>$1
$ ./test.py > out.txt 2>$1
$ ./test.py &> out.txt
$ ./test.py >& out.txt
# out.txt: error, output

$ cat 0< out.txt
$ cat < out.txt
# = cat out.txt

command


exec

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
exec rbash
# Replace the current bash shell with rbash, the restricted bash login shell. Because the original bash shell is destroyed, the user will not be returned to a privileged bash shell when rbash exits.

exec > output.txt
# Redirect all output to the file output.txt for the current shell process.
# Redirections are a special case, and exec does not destroy the current shell process, but bash will no longer print output to the screen, writing it to the file instead. (This technique is much more useful in scripts — if the above command is executed in a script, all script output will be written to output.txt.)

exec 3< myinfile.txt
# Open myinfile.txt for reading ("<") on file descriptor 3.
# explicitly opening a file descriptor
# After running the above command, you can read a line of myinfile.txt by running the read command with the -u option:

read -u 3 mydata
# "-u 3" tells read to get its data from file descriptor 3, which refers to myinfile.txt.
# The contents are read, one line at a time, into the variable mydata. This would be useful if used as part of a while loop, for example.



# open and close new file descriptors.

exec 4> out.txt
# opens out.txt for writing (">") on file descriptor 4.

exec 3<&-
# Close ("&-") the open read descriptor ("<") number 3.

exec 4>&-
# Close the open write descriptor (">") number 4.

exec 5<> myfile.txt
# Open myfile.txt for reading and writing ("<>") as file descriptor 5.

exec 5<>&-
# Close open read/write descriptor 5.

exec 6>> myappendfile.txt
# Open myappendfile.txt for appending (">>") as file descriptor 6.

exec {myfd}> out.txt
# Open myfile.txt for writing. A new file descriptor number, chosen automatically, is assigned to the variable myfd.

echo Text >&myfd
# Echo the text "Text" and redirect the output to the file (in this case, myfile.txt) described by the write descriptor (">") whose number is obtained by dereferencing ("&") the variable named myfd.

.

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.