Because bash is the standard default shell interpreter for Linux, it can be said that bash is the foundation of shell programming.

This article focuses on bash syntax, not Linux directives.

: Notebook: This article has been archived to: “blog” : Keyboard: The source code for this article has been archived to linux-tutorial

█ █ █ █ █ █ █ ╗ █ █ ╗ █ █ ╗ █ █ █ █ █ █ █ ╗ █ █ ╗ █ █ ╗ █ █ ╔ ═ ═ ═ ═ ╝ █ █ ║ █ █ ║ █ █ ╔ ═ ═ ═ ═ ╝ █ █ ║ █ █ ║ █ █ █ █ █ █ █ ╗ █ █ █ █ █ █ █ ║ █ █ █ █ █ ╗ █ █ ║ █ █ ║ ╚ ═ ═ ═ ═ █ █ ║ █ █ ╔ ═ ═ █ █ ║ █ █ ╔ ═ ═ ╝ █ █ ║ █ █ ║ █ █ █ █ █ █ █ ║ █ █ ║ █ █ ║ █ █ █ █ █ █ █ ╗ █ █ █ █ █ █ █ ╗ █ █ █ █ █ █ █ ╗Copy the code

1. Introduction

1.1. What is a shell

  • Shell is a program written in C language, which is the bridge for users to use Linux.
  • Shell is both a command language and a programming language.
  • A Shell is an application that provides an interface through which users can access the services of the Linux kernel.

Ken Thompson’s SH was the first Unix Shell, and Windows Explorer is a typical graphical interface Shell.

1.2. What is a shell script

A Shell script is a script program written for a Shell. The file suffix is.sh.

The industry usually refers to shell script, but shell and shell script are two different concepts.

1.3. The Shell environment

Shell programming, like Java and PHP programming, requires only a text editor that can write the code and a script interpreter that can interpret the execution.

There are many types of Shell interpreters. The common ones are:

  • Sh – Bourne Shell. Sh is the standard default SHELL for Unix.
  • Bash – Bourne Again Shell. Bash is the standard default Shell for Linux.
  • Fish – Intelligent and user friendly command line shell.
  • Xiki – makes the shell console friendlier and more powerful.
  • ZSH – powerful shell and scripting language.

Specifies the script interpreter

In shell scripts, #! Tell the system that the program specified in the following path is the Shell interpreter that interprets the script file. #! It’s called a shebang (also known as a Hashbang).

So, you should see comments like this in the shell:

  • Specifies the sh interpreter
#! /bin/shCopy the code
  • Specify the bash interpreter
#! /bin/bashCopy the code

Pay attention to

The above method of specifying the interpreter is common, but sometimes you may also see the following:

#! /usr/bin/env bashCopy the code

The benefit of this is that the system automatically looks for the program you specify (bash in this case) in the PATH environment variable. You should use this notation as much as possible compared to the first notation, because the path of the program is uncertain. As an added benefit, the operating system’s PATH variable can be configured to point to another version of the program. For example, after installing a new version of bash, we might “hide” the old version by adding its PATH to PATH. If you just use #! /bin/bash, then the system selects the older version of bash to execute the script. /usr/bin/env bash, the new version is used.

1.4. Model

The shell has two modes: interactive and non-interactive.

Interactive mode

In simple terms, you can think of the shell’s interactive mode as executing the command line.

The shell is in interactive mode when you see something like this:

user@host:~$
Copy the code

Next, you can type a series of Linux commands such as ls, grep, CD, mkdir, rm, and so on.

Non-interactive mode

In simple terms, you can think of the shell’s non-interactive mode as executing shell scripts.

In non-interactive mode, the shell reads a command from a file or pipe and executes it.

When the shell interpreter finishes executing the last command in the file, the shell process terminates and returns to the parent process.

You can make the shell run in non-interactive mode with the following command:

sh /path/to/script.sh
bash /path/to/script.sh
source /path/to/script.sh
./path/to/script.sh
Copy the code

In the example above, script.sh is a plain text file that contains commands that the shell interpreter can recognize and execute, and sh and bash are shell interpreter programs. You can create script.sh using any editor you like (vim, Nano, Sublime Text, Atom, etc.).

Where, source /path/to/script.sh and./path/to/script.sh are equivalent.

In addition, you can execute scripts directly by adding executable permissions to files using the chmod command:

chmod +x /path/to/script.sh # Give execute permission to the script
/path/to/test.sh
Copy the code

This method requires that the first line of the script file must indicate the program to run the script. For example:

: Keyboard: Example source code Helloworld.sh

#! /usr/bin/env bash
echo "Hello, world!"
Copy the code

In the example above, we used the useful command echo to print the string to the screen.

Basic grammar

2.1. The interpreter

Although I mentioned the #! , but in the spirit of saying important things three times, here it is again:

In shell scripts, #! Tell the system that the program specified in the following path is the Shell interpreter that interprets the script file. #! It’s called a shebang (also known as a Hashbang).

#! Determines that the script can be executed as a stand-alone executable without having to type sh, bash, Python, PHP, etc. before the terminal.

You can specify shell interpreter as bash in either of the following ways. The second way is better
#! /bin/bash
#! /usr/bin/env bashCopy the code

2.2. The annotation

Comments can explain what your code does and why.

In shell syntax, comments are special statements that are ignored by the shell interpreter.

  • One-line comments – to#The beginning, the end of the line.
  • Multi-line comments – to:<<EOFThe beginning,EOFThe end.

: Keyboard: Example source code comment-demo.sh

# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
Shell comment example
# author: zp
# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -

# echo 'This is a single line comment'

########## This is the dividing line ##########

:<<EOF
echo 'This is a multi-line comment.'
echo 'This is a multi-line comment.'
echo 'This is a multi-line comment.'
EOF
Copy the code

2.3. The echo

Echo is used for the output of strings.

Output a normal string:

echo "hello, world"
# Output: hello, world
Copy the code

Output a string containing variables:

echo "hello, \"zp\""
# Output: hello, "zp"
Copy the code

Output a string containing variables:

name=zp
echo "hello, \"${name}\ ""
# Output: hello, "zp"
Copy the code

Output a string with a newline:

# Prints a string with newlines
echo "YES\nNO"
# Output: YES\nNO

echo -e "YES\nNO" # -e enables escape
# Output:
# YES
# NO
Copy the code

Print a string with no newlines:

echo "YES"
echo "NO"
# Output:
# YES
# NO

echo -e "YES\c" # -e turns on escape \c without line feed
echo "NO"
# Output:
# YESNO
Copy the code

The output is redirected to a file

echo "test" > test.txt
Copy the code

Output execution result

echo `pwd`
# Output:(current directory path)
Copy the code

: Keyboard: Example source code echo-demo.sh

2.4. The printf

Printf is used to format the output string.

By default, printf does not automatically add a newline as echo does. If you need a newline, you can manually add \n.

: Keyboard: Example source code printf-demo.sh

# quotes
printf '%d %s\n' 1 "abc"
# Output:1 abc

# double quotation marks
printf "%d %s\n" 1 "abc"
# Output:1 abc

# no quotes
printf %s abcdef
# Output: abcdef(no line feed)

The # format specifies only one argument, but any additional arguments are still printed in that format
printf "%s\n" abc def
# Output:
# abc
# def

printf "%s %s %s\n" a b c d e f g h i j
# Output:
# a b c
# d e f
# g h i
# j

If there are no arguments, then %s is NULL and %d is 0
printf "%s and %d \n"
# Output:
# and 0

# Format output
printf "%-10s %-8s %-4s\n"Name gender weight kgprintf - 8-10 "% s % s % 4.2 f \ n"The guo jing male 66.1234printf - 8-10 "% s % s % 4.2 f \ n"Yang2 guo4 male 48.6543printf - 8-10 "% s % s % 4.2 f \ n"Guo Fu female 47.9876# Output:
Name gender weight kg
Guo Jing, Nan 66.12
# Yang Guo male 48.65
# Guo Fu Female 47.99
Copy the code

Escape character of printf

The sequence instructions
\a Warning character, usually the ASCII BEL character
\b back
\c Suppress (do not display) any ending newline characters in the output (valid only in the argument string controlled by the %b format indicator), and any characters left in the argument, any subsequent arguments, and any characters left in the format string are ignored
\f FormFeed
\n A newline
\r Carriage return
\t Horizontal TAB
\v Vertical TAB
\ \ A literal backslash character
\ddd A character representing a 1 – to 3-digit octal value. Valid only in the format string
\0ddd Octal value characters representing 1 to 3 digits

3. The variable

As with many programming languages, you can create variables in bash.

There are no data types in Bash, and variables in Bash can hold a number, a character, a string, and so on. There is no need to declare variables in advance; assigning a value to a variable creates the variable directly.

3.1. Variable naming principles

  • The name can contain only letters, digits, and underscores (_). The first character cannot start with a digit.
  • An underscore (_) can be used.
  • No punctuation.
  • You cannot use keywords in bash (use the help command to view reserved keywords).

3.2. Declare variables

The syntax for accessing variables is: ${var} and $var.

Curly braces around variable names are optional. They are used to help the interpreter identify variable boundaries, so they are recommended.

word="hello"
echo ${word}
# Output: hello
Copy the code

3.3. Read-only variables

Using the readonly command, you can define a variable as read-only. The value of a read-only variable cannot be changed.

rword="hello"
echo ${rword}
readonly rword
# rword="bye
Copy the code

3.4. Delete variables

The unset command is used to delete variables. A variable that has been deleted cannot be used again. The unset command cannot delete read-only variables.

dword="hello"  # Declare variables
echo ${dword}  # Output variable values
# Output: hello

unset dword    # Delete variable
echo ${dword}
# Output: (empty)
Copy the code

3.5. Variable types

  • Local variables – Local variables are variables that are valid only within a script. They cannot be accessed by other programs or scripts.
  • The environment variable– Environment variables are visible to all programs or scripts in the current shell session. Creating them is similar to creating local variables, but usingexportShell scripts can also define environment variables.

Common environment variables:

variable describe
$HOME The user directory of the current user
$PATH A semicolon-separated list of directories into which the shell looks for commands
$PWD Current working directory
$RANDOM An integer between 0 and 32767
$UID The value is the ID of the current user
$PS1 Main system input prompt
$PS2 Secondary system input prompt

Here is a more comprehensive list of Bash environment variables.

3.6. Variable example source code

⌨️ Example source code variable-demo.sh

4. The string

4.1. Single and double quotes

Shell strings can be in single quotes ”, double quotes ” or no quotes.

  • Features of single quotation marks
    • Variables are not recognized in single quotes
    • Single quotes are not allowed within single quotes (escape characters are not allowed), but can be used in pairs as string concatenation.
  • Features of double quotation marks
    • Identify variables in double quotes
    • Escape characters can appear in double quotes

Above all, double quotation marks are recommended.

4.2. Concatenation of strings

# use single quotation marks
name1='white'
str1='hello, '${name1}' '
str2='hello, ${name1}'
echo ${str1}_${str2}
# Output:
# hello, white_hello, ${name1}

# use double quotation marks
name2="black"
str3="hello, "${name2}""
str4="hello, ${name2}"
echo ${str3}_${str4}
# Output:
# hello, black_hello, black
Copy the code

4.3. Get the string length

text="12345"
echo ${#text}
# Output:
# 5
Copy the code

4.4. Intercept substrings

text="12345"
echo ${text:2:2}
# Output:
# 34
Copy the code

Intercepts two characters, starting with the third character

4.5. Find substrings

#! /usr/bin/env bash
text="hello"
echo `expr index "${text}" ll`

# Execute: ./str-demo5.sh
# Output:
# 3
Copy the code

Look for the starting position of the LL subcharacter in the Hello string.

4.6. String example source code

⌨️ Example source code string-demo.sh

An array of 5.

Bash supports only one-dimensional arrays.

Array indices start at 0 and can be integers or arithmetic expressions whose value should be greater than or equal to 0.

5.1. Creating arrays

# Different ways to create arrays
nums=([2]=2 [0]=0 [1]=1)
colors=(red yellow "dark blue")
Copy the code

5.2. Accessing array elements

  • Accessing a single element of an array:
echo ${nums[1]}
# Output: 1
Copy the code
  • Access all elements of an array:
echo ${colors[*]}
# Output: red yellow dark blue

echo ${colors[@]}
# Output: red yellow dark blue
Copy the code

There is an important (and subtle) difference between the two lines above:

To print a single line for each element in the array, we use the printf command:

printf "+ %s\n" ${colors[*]}
# Output:
# + red
# + yellow
# + dark
# + blue
Copy the code

Why are dark and blue on each line? Try wrapping it in quotation marks:

printf "+ %s\n" "${colors[*]}"
# Output:
# + red yellow dark blue
Copy the code

Now all the elements are printed on one line — which is not what we want! Let’s try ${colors[@]}

printf "+ %s\n" "${colors[@]}"
# Output:
# + red
# + yellow
# + dark blue
Copy the code

Within quotes, ${colors[@]} extends each element in the array to a single parameter; Whitespace in array elements is preserved.

  • Access partial elements of an array:
echo ${nums[@]:0:2}
# Output:
# 0 1
Copy the code

In the example above, ${array[@]} is extended to the entire array, and :0:2 takes all the elements of length 2 from 0.

5.3. Accessing array length

echo ${#nums[*]}
# Output:
# 3
Copy the code

5.4. Add elements to an array

Adding elements to an array is also simple:

colors=(white "${colors[@]}" green black)
echo ${colors[@]}
# Output:
# white red yellow dark blue green black
Copy the code

In the example above, ${colors[@]} is extended to the entire array and substituted into the compound assignment statement, and then the assignment to colors of the array overrides its original value.

5.5. Remove elements from an array

To remove an element from an array, use the unset command:

unset nums[0]
echo ${nums[@]}
# Output:
# 1 2
Copy the code

5.6. Array sample source code

: Keyboard: Example source code Array-demo.sh

6. Operator

6.1. Arithmetic operators

The following table lists the common arithmetic operators, assuming that the variable x is 10 and the variable y is 20:

The operator instructions For example,
+ add expr $x + $yThat’s 30.
subtraction expr $x - $ySo it’s minus 10.
* The multiplication expr $x * $yThat’s 200.
/ division expr $y / $xThat’s 2.
% Take more than expr $y % $xThat’s 0.
= The assignment x=$yAssigns the value of the variable y to x.
= = The same. Used to compare two numbers. Returns true if they are the same. [ $x == $y ]Returns false.
! = Is not equal. Used to compare two numbers; return true if they are different. [ $x != $y ]Returns true.

$x==$y; $x==$y; $x==$y; $x==$y;

: Keyboard: Example source operator-demo.sh

x=10
y=20

echo "x=${x}, y=${y}"

val=`expr ${x} + ${y}`
echo "${x} + ${y} = $val"

val=`expr ${x} - ${y}`
echo "${x} - ${y} = $val"

val=`expr ${x}A \ *${y}`
echo "${x} * ${y} = $val"

val=`expr ${y} / ${x}`
echo "${y} / ${x} = $val"

val=`expr ${y} % ${x}`
echo "${y} % ${x} = $val"

if [[ ${x}= =${y} ]]
then
  echo "${x} = ${y}"
fi
if [[ ${x}! =${y} ]]
then
  echo "${x}! =${y}"
fi

# Execute: ./operator-demo.sh
# Output:
# x=10, y=20
# 10 + 20 = 30
# 10-20 = -10
# 10 * 20 = 200
# 20/10 = 2
# 20%10 = 0
# 10! = 20
Copy the code

6.2. Relational operators

Relational operators only support numbers, not strings, unless the value of the string is a number.

The following table lists the commonly used relational operators, assuming the variable x is 10 and the variable y is 20:

The operator instructions For example,
-eq Tests if two numbers are equal. If they are, return true. [ $a -eq $b ]Returns false.
-ne Checks if two numbers are equal. If they are not, return true. [ $a -ne $b ]Returns true.
-gt Checks if the number on the left is greater than the number on the right, and returns true if it is. [ $a -gt $b ]Returns false.
-lt Checks if the number on the left is less than the number on the right, and returns true if it is. [ $a -lt $b ]Returns true.
-ge Checks if the number on the left is greater than or equal to the number on the right, and returns true if it is. [ $a -ge $b ]Returns false.
-le Checks if the number on the left is less than or equal to the number on the right, and returns true if it is. [ $a -le $b ]Returns true.

: Keyboard: Example source operator-demo2.sh

x=10
y=20

echo "x=${x}, y=${y}"

if [[ ${x} -eq ${y}]].then
   echo "${x} -eq ${y}X = y"
else
   echo "${x} -eq ${y}X does not equal y"
fi

if [[ ${x} -ne ${y}]].then
   echo "${x} -ne ${y}X does not equal y"
else
   echo "${x} -ne ${y}X = y"
fi

if [[ ${x} -gt ${y}]].then
   echo "${x} -gt ${y}X is greater than y"
else
   echo "${x} -gt ${y}X is not greater than y"
fi

if [[ ${x} -lt ${y}]].then
   echo "${x} -lt ${y}X < y"
else
   echo "${x} -lt ${y}X is not less than y"
fi

if [[ ${x} -ge ${y}]].then
   echo "${x} -ge ${y}X is greater than or equal to y"
else
   echo "${x} -ge ${y}X < y"
fi

if [[ ${x} -le ${y}]].then
   echo "${x} -le ${y}X is less than or equal to y"
else
   echo "${x} -le ${y}X is greater than y"
fi

# Execute: ./operator-demo2.sh
# Output:
# x=10, y=20
Eq 20: x does not equal y
# 10 -ne 20: x does not equal y
# 10 -gt 20: x is not greater than y
# 10 -lt 20: x is less than y
# 10-ge 20: x is less than y
# 10 -le 20: x is less than or equal to y
Copy the code

6.3. Boolean operators

The following table lists the common Boolean operators, assuming that the variable x is 10 and the variable y is 20:

The operator instructions For example,
! No operation, return false if the expression is true, or true otherwise. [ ! false ]Returns true.
-o Returns true if one of the expressions is true. [ $a -lt 20 -o $b -gt 100 ]Returns true.
-a Returns true if both expressions are true. [ $a -lt 20 -a $b -gt 100 ]Returns false.

:keyboard: Example source operator-demo3.sh

x=10
y=20

echo "x=${x}, y=${y}"

if [[ ${x}! =${y}]].then
   echo "${x}! =${y}X does not equal y"
else
   echo "${x}! =${y}X = y"
fi

if [[ ${x} -lt 100 && ${y} -gt15]];then
   echo "${x}Less than 100 and${y}> 15: returns true"
else
   echo "${x}Less than 100 and${y}> 15: return false"
fi

if [[ ${x} -lt100 | |${y} -gt100]];then
   echo "${x}Less than 100 or${y}> 100: returns true"
else
   echo "${x}Less than 100 or${y}> 100: return false"
fi

if [[ ${x} -lt5 | |${y} -gt100]];then
   echo "${x}Less than 5 or${y}> 100: returns true"
else
   echo "${x}Less than 5 or${y}> 100: return false"
fi

# Execute: ./operator-demo3.sh
# Output:
# x=10, y=20
# 10! = 20: x does not equal y
# 10 less than 100 and 20 greater than 15: returns true
# 10 less than 100 or 20 greater than 100: returns true
# 10 < 5 or 20 > 100: returns false
Copy the code

6.4. Logical operators

The following describes the Shell’s logical operators, assuming that the variable x is 10 and the variable y is 20:

The operator instructions For example,
&& The logic of the AND [[ ${x} -lt 100 && ${y} -gt 100 ]]Returns false
|| The logic of the OR [[ ${x} -lt 100 || ${y} -gt 100 ]]Returns true

: Keyboard: Example source operator-demo4.sh

x=10
y=20

echo "x=${x}, y=${y}"

if [[ ${x} -lt 100 && ${y} -gt100]]then
   echo "${x} -lt 100 && ${y}-gt 100 returns true"
else
   echo "${x} -lt 100 && ${y}-gt 100 returns false"
fi

if [[ ${x} -lt100 | |${y} -gt100]]then
   echo "${x} -lt 100 || ${y}-gt 100 returns true"
else
   echo "${x} -lt 100 || ${y}-gt 100 returns false"
fi

# Execute: ./operator-demo4.sh
# Output:
# x=10, y=20
# 10-lt 100 && 20-gt 100 returns false
20 # 10 - lt 100 | | - gt 100 returns true
Copy the code

6.5. String operators

The following table lists the commonly used string operators, assuming variable A is “ABC” and variable B is “efg” :

The operator instructions For example,
= Checks if two strings are equal. If they are, return true. [ $a = $b ]Returns false.
! = Checks if two strings are equal. If they are not, return true. [ $a != $b ]Returns true.
-z Checks if the string length is 0. If 0, returns true. [ -z $a ]Returns false.
-n Checks if the string length is 0. Returns true if it is not. [ -n $a ]Returns true.
str Checks if the string is empty. Returns true if it is not. [ $a ]Returns true.

: Keyboard: Example source operator-demo5.sh

x="abc"
y="xyz"


echo "x=${x}, y=${y}"

if [[ ${x} = ${y}]].then
   echo "${x} = ${y}X = y"
else
   echo "${x} = ${y}X does not equal y"
fi

if [[ ${x}! =${y}]].then
   echo "${x}! =${y}X does not equal y"
else
   echo "${x}! =${y}X = y"
fi

if [[ -z ${x}]].then
   echo "-z ${x}: string length 0"
else
   echo "-z ${x}: string length is not 0"
fi

if [[ -n "${x}"]].then
   echo "-n ${x}: string length is not 0"
else
   echo "-n ${x}: string length 0"
fi

if [[ ${x}]].then
   echo "${x}: the string is not empty"
else
   echo "${x}: the string is empty"
fi

# Execute: ./operator-demo5.sh
# Output:
# x=abc, y=xyz
# ABC = xyz: x does not equal y
# abc ! = xyz: x does not equal y
# -z ABC: The length of the string is not 0
# -n ABC: The length of the string is not 0
# ABC: The string is not empty
Copy the code

6.6. File test operators

The file test operator is used to detect various properties of Unix files.

Attribute detection is described as follows:

The operator instructions For example,
-b file Checks if the file is a block device file and returns true if it is. [ -b $file ]Returns false.
-c file Checks if the file is a character device file and returns true if it is. [ -c $file ]Returns false.
-d file Checks if the file is a directory and returns true if it is. [ -d $file ]Returns false.
-f file Checks if the file is a normal file (neither a directory nor a device file) and returns true if it is. [ -f $file ]Returns true.
-g file Checks if the file has the SGID bit set, and returns true if so. [ -g $file ]Returns false.
-k file Checks whether the file has Sticky bits set and returns true if so. [ -k $file ]Returns false.
-p file Checks if the file is a named pipe and returns true if it is. [ -p $file ]Returns false.
-u file Checks if the file has the SUID bit set and returns true if so. [ -u $file ]Returns false.
-r file Checks whether the file is readable and returns true if it is. [ -r $file ]Returns true.
-w file Checks if the file is writable and returns true if it is. [ -w $file ]Returns true.
-x file Checks whether the file is executable and returns true if it is. [ -x $file ]Returns true.
-s file Checks if the file is empty (if the file size is greater than 0), returns true if it is not empty. [ -s $file ]Returns true.
-e file Detects whether the file (including the directory) exists and returns true if it does. [ -e $file ]Returns true.

: Keyboard: Example source operator-demo6.sh

file="/etc/hosts"

if [[ -r ${file}]].then
   echo "${file}File readable ""
else
   echo "${file}File unreadable"
fi
if [[ -w ${file}]].then
   echo "${file}Document writable"
else
   echo "${file}File cannot be written."
fi
if [[ -x ${file}]].then
   echo "${file}File executable ""
else
   echo "${file}File unexecutable"
fi
if [[ -f ${file}]].then
   echo "${file}File is a common file ""
else
   echo "${file}File is a special file"
fi
if [[ -d ${file}]].then
   echo "${file}File is a directory."
else
   echo "${file}File is not a directory."
fi
if [[ -s ${file}]].then
   echo "${file}File not empty"
else
   echo "${file}File is empty ""
fi
if [[ -e ${file}]].then
   echo "${file}File exists ""
else
   echo "${file}File does not exist."
fi

# Execute: ./operator-demo6.sh
The Output may vary according to the actual situation of the file.
The /etc/hosts file is readable
The /etc/hosts file is writable
The # /etc/hosts file is not executable
The # /etc/hosts file is a common file
# /etc/hosts file is not a directory
The /etc/hosts file is not empty
# /etc/hosts file exists
Copy the code

7. Control statements

7.1. Conditional statements

As with other programming languages, conditional statements in Bash allow us to determine whether an operation will be executed. The result depends on an expression wrapped in [[]].

Expressions wrapped in [[]] ([] in sh) are called detection commands or primitives. These expressions help us detect the result of a condition. This is where you’ll find the answer to the difference between single and double brackets in bash.

There are two different conditional expressions: if and case.

if

(1) If statement

If is used in the same way as any other language. If the expression in brackets is true, then the code between then and FI is executed. Fi marks the end of the conditional block.

Write # in one line
if[[1-eq1]];then echo "1 -eq 1 result is: true"; fi
# Output: 1 -eq 1 result is: true

Write the # in multiple lines
if [[ "abc" -eq "abc" ]]
then
  echo ""abc" -eq "abc" result is: true"
fi
# Output: abc -eq abc result is: true
Copy the code

(2) If else statement

Again, we can use if.. Else statements, such as:

if[[2-ne1]];then
  echo "true"
else
  echo "false"
fi
# Output: true
Copy the code

(3) If elif else statement

Sometimes, if.. Can’t meet our requirements. Don’t forget the if.. elif.. Else is easy to use.

x=10
y=20
if [[ ${x} > ${y}]].then
   echo "${x} > ${y}"
elif [[ ${x} < ${y}]].then
   echo "${x} < ${y}"
else
   echo "${x} = ${y}"
fi
# Output: 10 < 20
Copy the code

: Keyboard: Example source code if-demo.sh

case

If you are faced with many situations and need to take different actions, then using case is more useful than nested ifs. Using case to solve complex conditional judgments looks something like this:

: Keyboard: Example source code case-demo.sh

exec
case ${oper} in
  "+")
    val=`expr ${x} + ${y}`
    echo "${x} + ${y} = ${val}"
  ;;
  "-")
    val=`expr ${x} - ${y}`
    echo "${x} - ${y} = ${val}"
  ;;
  "*")
    val=`expr ${x}A \ *${y}`
    echo "${x} * ${y} = ${val}"
  ;;
  "/")
    val=`expr ${x} / ${y}`
    echo "${x} / ${y} = ${val}"
  ;;
  *)
    echo "Unknown oper!"
  ;;
esac
Copy the code

Each case is an expression that matches a pattern. | used to split multiple patterns,) used to end a pattern sequence. The command corresponding to the first matching pattern will be executed. * represents any pattern that does not match the given pattern above. Between the command block to use; Space.

7.2. Loop statements

Loops are not surprising. As in other programming languages, loops in bash are blocks of code that iteratively execute as long as the control condition is true.

There are four types of loops in Bash: for, while, until, and SELECT.

forcycle

For is very much like its C sister. It looks like this:

for arg in elem1 elem2 ... elemN
do
  # # #
done
Copy the code

During each loop, the arG is assigned values from elem1 through elemN. These values can also be wildcard or curly brace extensions.

Of course, we could write the for loop on one line, but this would require a semicolon to precede the do, like this:

for i in{1.. 5};do echo $i; done
Copy the code

Also, if you feel that for.. in.. Do is a little weird for you, so you can also use for like C, like:

for (( i = 0; i < 10; i++ )); do
  echo $i
done
Copy the code

For comes in handy when we want to do the same for all files in a directory. For example, if we wanted to move all.bash files to the script folder and give them executable permissions, our script could read:

DIR=/home/zp
for FILE in ${DIR}/*.sh; do
  mv "$FILE" "${DIR}/scripts"
done
# copy all sh files in /home/zp directory to /home/zp/scripts
Copy the code

: Keyboard: Example source code for-demo.sh

whilecycle

The while loop detects a condition and executes a sequence of commands as long as the condition is true. The condition being tested is similar to if.. The primitives used in then are the same. So a while loop would look like this:

while [[ condition ]]
do
  # # #
done
Copy the code

As with the for loop, if we put the do on one line with the condition being tested, we must add a semicolon before the do.

Here’s an example:

### Square every number between 0 and 9
x=0
while [[ ${x} -lt10]];do
  echo $((x * x))
  x=$((x + 1))
done
# Output:
# 0
# 1
# 4
# 9
# 16
# 25
# 36
# 49
# 64
# 81
Copy the code

: Keyboard: Example source code while-demo.sh

untilcycle

The until loop is the opposite of the while loop. It also checks for a test condition like while, but executes as long as the condition is false:

x=0
until [[ ${x} -ge 5 ]]; do
  echo ${x}
  x=`expr ${x}+ 1 `done
# Output:
# 0
# 1
# 2
# 3
# 4
Copy the code

: Keyboard: Example source code until-demo.sh

selectcycle

The select loop helps us organize a user menu. Its syntax is almost identical to the for loop:

select answer in elem1 elem2 ... elemN
do
  # # #
done
Copy the code

Select will print elem1.. The elemns and their serial numbers come to the screen, after which the user is prompted for input. You usually see $? (PS3 variable). The user’s selection result will be saved in the Answer. If the answer is one in 1.. N, then the statement will be executed, followed by the next iteration — we can use the break statement if we don’t want this.

A possible instance might look like this:

#! /usr/bin/env bash
PS3="Choose the package manager: "
select ITEM in bower npm gem pip
do
echo -n "Enter the package name: " && read PACKAGE
case ${ITEM} in
  bower) bower install ${PACKAGE} ;;
  npm) npm install ${PACKAGE} ;;
  gem) gem install ${PACKAGE} ;;
  pip) pip install ${PACKAGE} ;;
esac
break # Avoid infinite loops
done
Copy the code

This example starts by asking the user what package manager he wants to use. Next, you are asked what packages you want to install, and finally you perform the installation.

Running this script yields the following output:

$ ./my_script
1) bower
2) npm
3) gem
4) pip
Choose the package manager: 2
Enter the package name: gitbook-cli
Copy the code

: Keyboard: Example source select-demo.sh

breakcontinue

If you want to prematurely end a loop or skip a loop execution, you can use the shell’s break and continue statements to do so. They can be used in any loop.

The break statement is used to prematurely end the current loop.

The continue statement is used to skip an iteration.

: Keyboard: Example source code break-demo.sh

# Find the first positive integer within 10 that divides 2 and 3
i=1
while [[ ${i} -lt10]];do
  if [[ $((i % 3)) -eq 0 ]] && [[ $((i % 2)) -eq0]];then
    echo ${i}
    break;
  fi
  i=`expr ${i}+ 1 `done
# Output: 6
Copy the code

: Keyboard: Example source code continue-demo.sh

Print odd numbers up to 10
for (( i = 0; i < 10; i ++ )); do
  if [[ $((i % 2)) -eq0]];then
    continue;
  fi
  echo ${i}
done
# Output:
# 1
# 3
# 5
# 7
# 9
Copy the code

8. Function

The bash function definition syntax is as follows:

[ function ] funname [()] {
    action;
    [returnint; ] }Copy the code

Bulbs: details:

  1. When a function is defined,functionKeywords are optional.
  2. Function return value -return Returns the value returned by a function. The return value can only be an integer (0-255). If you do not add a return statement, the shell returns the result of the last command.
  3. The return value from a function passes after the function is called$?To obtain.
  4. All functions must be defined before they are used. This means that the function must be placed at the beginning of the script until it is first discovered by the shell interpreter. A function is called only by its function name.

: Keyboard: Example source code function-demo.sh

#! /usr/bin/env bash
calc(){
  PS3="choose the oper: "
  select oper in+ - \ * /# Generate operator selection menu
  do
  echo -n "enter first num: " && read x # Read input parameters
  echo -n "enter second num: " && read y # Read input parameters
  exec
  case ${oper} in
    "+")
      return $((${x} + ${y}));"-")
      return $((${x} - ${y}));"*")
      return $((${x} * ${y}));"/")
      return $((${x} / ${y})); *)echo "${oper} is not support!"
      return0;;esac
  break
  done
}
calc
echo "the result is: $?" # $? Gets the value returned by the calc function
Copy the code

Execution result:

/ $.function-demo.sh
1) +
2) -
3) *
4) /
choose the oper: 3
enter first num: 10
enter second num: 10
the result is: 100
Copy the code

8.1. Positional parameters

Positional arguments are variables created when a function is called and passed arguments to it.

Variation table of positional parameters:

variable describe
$0 The name of the script
The $1... $9 List of parameters 1 through 9
The ${10}... ${N} The 10th to N parameter list
$* or $@ In addition to$0All positional parameters outside
$# Do not include$0Number of positional parameters within
$FUNCNAME Function name (value only inside the function)

: Keyboard: Example source code function-demo2.sh

#! /usr/bin/env bash
x=0
if [[ -n The $1]].then
  echo "The first argument is:The $1"
  x=The $1
else
  echo "The first argument is null."
fi

y=0
if [[ -n $2]].then
  echo "The second parameter is:$2"
  y=$2
else
  echo "The second parameter is empty."
fi

paramsFunction() {echo "The first argument to the function is:The $1"
  echo "The second argument to the function:$2"
}
paramsFunction ${x} ${y}
Copy the code

Execution result:

/ $.function-demo2.sh the first argument is empty. The second argument is empty. The first argument to the function is 0function-demo2.sh 10 20 The first argument is: 10. The second argument is: 20. The first parameter in the function is: 10Copy the code

Run./ varial-demo4. sh hello world, and then pass $1, $2… Read the first parameter, the second parameter…

8.2. Function processing parameters

In addition, there are several special characters used to handle arguments:

Processing parameters instructions
$# Number of returned parameters
$* Return all parameters
? ID of the process where the script is running
$! The ID number of the last process running in the background
$@ Return all parameters
$- Returns the current option used by the Shell. It has the same function as the set command.
$? Function return value

: Keyboard: Example source code function-demo3.sh

runner() {
  return 0
}

name=zp
paramsFunction() {echo "The first argument to the function is:The $1"
  echo "The second argument to the function:$2"
  echo "Number of arguments passed to the script:$#"
  echo "All parameters:"
  printf "+ %s\n" "$*"
  echo "ID of the current process in which the script is running:?"
  echo "ID number of last process running in the background: $!"
  echo "All parameters:"
  printf "+ %s\n" "$@"
  echo "Current option used by Shell: $-"
  runner
  echo "Return value from function runner: $?"
}
paramsFunction 1 "abc" "hello, \"zp\""
# Output:
The function takes the first argument: 1
The second input to the function is ABC
# Number of arguments passed to script: 3
# All parameters:
# + 1 abc hello, "zp"
# Script is running on process 26400
# ID of last process running in background:
# All parameters:
# + 1
# + abc
# + hello, "zp"
# Current option used by Shell: hB
The # runner function returns 0
Copy the code

9. The Shell extension

The extension occurs after a line of commands has been broken up into tokens. In other words, extensions are a mechanism for performing mathematical operations, storing the results of commands, and so on.

You can read more details about shell extensions if you are interested.

Curly brace extension

The curly bracket extension makes it possible to generate arbitrary strings. This is similar to filename extensions. Here’s an example:

echo beg{i,a,u}n ### begin began begun
Copy the code

Curly brace extensions can also be used to create an interval that can be iterated through.

echo{0.. 5}### 0 1 2 3 4 5
echo{00.. 8.. 2}### 00 02 04 06 08
Copy the code

Command substitution

Command substitution allows us to evaluate a command and replace its value with another command or variable assignment expression. When a command is surrounded by ‘ ‘or $(), a command substitution is performed. Here’s an example:

now=`date +%T`
### or
now=$(date +%T)

echo $now # # # 19:08:26
Copy the code

Count extension

In bash, performing arithmetic operations is very convenient. Arithmetic expressions must be wrapped in $(()). The format of arithmetic extensions is:

result=$(( ((10 + 5*3) - 7) / 2 ))
echo $result # # # 9
Copy the code

In arithmetic expressions, variables need not be prefixed with $:

x=4
y=7
echo $(( x + y ))     # # # 11
echo $(( ++x + y++ )) # # # 12
echo $(( x + y ))     # # # 13
Copy the code

Single and double quotes

There is an important difference between single and double quotation marks. In double quotes, variable references or command permutations are expanded. Not in single quotes. Here’s an example:

echo "Your home: $HOME" ### Your home: /Users/<username>
echo 'Your home: $HOME' ### Your home: $HOME
Copy the code

When local and environment variables contain Spaces, be careful how they are extended in quotes. As a random example, suppose we use echo to output the user’s input:

INPUT="A string with strange whitespace."
echo $INPUT   ### A string with strange whitespace.
echo "$INPUT" ### A string with strange whitespace.
Copy the code

The first echo is called with five separate arguments — $INPUT is broken up into separate words, and echo prints a space between each word. In the second case, echo is called with just one argument (the entire value of $INPUT, including Spaces within it).

Here’s a more serious example:

FILE="Favorite Things.txt"
cat $FILE   ### Try to output two files: 'Favorite' and 'things.txt'
cat "$FILE" ### output a file: 'Favorite things.txt'
Copy the code

Although this problem can be solved by renating the FILE to Favorite -things.txt, what if the value came from an environment variable, a positional argument, or another command (find, cat, etc.)? Therefore, if the input may contain Spaces, be sure to wrap the expression in quotes.

10. Streams and redirects

Bash has powerful tools for handling collaboration between programs. Using streams, we can send the output of one program to another program or file, so we can easily log or do whatever else we want.

Pipelines give us the opportunity to create a conveyor belt that makes it possible to control the execution of a program.

Learning how to use these powerful, advanced tools is very, very important.

10.1. Input and output streams

Bash takes input and produces output in the form of a sequence or stream of characters. These streams can be redirected to a file or to another stream.

There are three file descriptors:

code The descriptor describe
0 stdin The standard input
1 stdout The standard output
2 stderr Standard error output

10.2. The redirection

Redirection allows us to control where the input to a command comes from and where the output goes. These operators are used when redirecting control flow:

Operator Description
> Redirected output
& > Redirect output and error output
& > > Redirects output and error output in additional form
< Redirected input
<< Here documentgrammar
<<< Here a string

Here are some examples of using redirects:

The result of ### ls will be written to list.txt
ls -l > list.txt

Append the output to list.txt
ls -a >> list.txt

### All error messages are written to errors.txt
grep da * 2> errors.txt

### reads input from errors.txt
less < errors.txt
Copy the code

10.3. /dev/nullfile

If you want to execute a command but do not want the output to appear on the screen, you can redirect the output to /dev/null:

$ command > /dev/null
Copy the code

/dev/null is a special file to which all content written is discarded; If you try to read from this file, nothing will be read. However, the /dev/null file is very useful, and redirecting the output of the command to it has the effect of “disallowing output”.

If you want to block stdout and stderr, you can write:

$ command > /dev/null 2>&1
Copy the code

11. Debug

The shell provides tools for debugging scripts.

If you want to run a script in debug mode, you can use a special option in its shebang:

#! /bin/bash options
Copy the code

Options are options that can change shell behavior. Here are some options that might be useful to you:

Short Name Description
-f noglob Disable file name expansion (globbing)
-i interactive Let the script tointeractionmode
-n noexec Read the command, but do not execute it (syntax checking)
-t Exit after the first command is executed
-v verbose Before executing each command, go tostderrOutput the command
-x xtrace Before executing each command, go tostderrPrints the command and its extended parameters

For example, if we specify -x in the script, for example:

#! /bin/bash -x

for (( i = 0; i < 3; i++ )); do
  echo $i
done
Copy the code

This prints out the value of the variable and some other useful information to stdout:

$ ./my_script
+ (( i = 0 ))
+ (( i < 3 ))
+ echo 0
0
+ (( i++  ))
+ (( i < 3 ))
+ echo 1
1
+ (( i++  ))
+ (( i < 3 ))
+ echo 2
2
+ (( i++  ))
+ (( i < 3 ))
Copy the code

Sometimes we need a part of the debug script. In this case, it is convenient to use the set command. This command enables or disables options. Use -to enable an option, + to disable an option:

: Keyboard: Example source code debug-demo.sh

# to open the debug
set -x
for (( i = 0; i < 3; i++ )); do
  printf ${i}
done
# to close the debug
set +x
# Output:
# + (( i = 0 ))
# + (( i < 3 ))
# + printf 0
# 0+ (( i++ ))
# + (( i < 3 ))
# + printf 1
# 1+ (( i++ ))
# + (( i < 3 ))
# + printf 2
# 2+ (( i++ ))
# + (( i < 3 ))
# + set +x

for i in{1.. 5};do printf ${i}; done
printf "\n"
# Output: 12345
Copy the code

12. More

: Notebook: This article has been filed to: “blog”

  • Awesome -shell, list of shell resources
  • Awesome -bash, list of bash resources
  • bash-handbook
  • Bash-guide is a basic bash guide
  • Bash-it provides a reliable framework for your daily use, development, and maintenance of shell scripts and custom commands
  • Dotfiles.github. IO, which has links to various dotFiles collections for bash and other shells and shell frameworks
  • Runoob Shell tutorial
  • Shellcheck is a static shell script analysis tool, which is essentially a bash/sh/ZSH Lint.

Finally, there are a lot of questions you can learn from under the bash TAB on Stack Overflow, and a good place to ask questions when you run into them.