Linux one "text" to get Shell programming

It's the graduation season again, and I have to find an internship job again. . .

Recently, I was looking for an internship job on a direct employment software. I saw that there are many jobs that require Shell programming, and I don’t know much about Shell programming, so I still have half a month of school time to learn it!


Shell is a command line interpreter, which receives application or user commands, and then calls the operating system kernel to perform operations!

Shell is also a very powerful programming language, easy to write, easy to debug, and flexible.

Shell can also be said to be a scripting language!

Shell is divided into bash and sh, both of them are actually the same thing from a macro perspective;


Table of contents

1. Getting Started with Shell Script

1.1 Three execution methods of Shell script

2. Variables

2.1 System predefined variables

2.2 Custom variables

2.2.1 Basic syntax

2.2.2 Variable definition rules

2.2.3 Case

2.3 Special variables

2.3.1 $n

2.3.2 $#

2.3.3 $*

2.3.4 $@

2.3.5 $?

3. Operators

4. Condition judgment

4.1 Basic syntax

4.2 Common Judgment Conditions

        4.2.1 Comparison between strings        

         4.2.2 Comparison between integers

        4.2.3 Judging by file permissions

       4.2.4 Judging by file type

4.3 Multi-condition judgment && || 

5. Process control

5.1 if judgment

5.1.1 Single branch

5.1.2 Multi-branch

5.1.3 Use of (( )) in if

5.2 case statement

5.2.1 Basic syntax

5.2.2 Case

5.3 for loop

5.3.1  for

5.3.2 for in (enhance the for loop, use a little more)

5.3.3 Difference between $* and $@

5.4 while loop

6. read read console input

Seven, function

7.1 System functions

7.1.1 basename

7.1.2 address

7.2 Custom functions

7.2.1 Basic syntax

7.2.2 Precautions

7.2.3 Case

8. Comprehensive application - realize file archiving

9. Getting Started with Regular Expressions

9.1 Regular matching

9.2 Commonly used special characters

9.2.1    ^

9.2.2    $

9.2.3   .

9.2.4   *

9.2.5 Character range (brackets): [ ]

9.2.6   \

9.3 Exercise, matching mobile phone numbers

10. Text processing tools

10.1   cut

10.1.1 Basic usage

10.1.2 Description of option parameters

10.1.3 Case

10.2   gawk

10.2.1 Basic usage

10.2.2 Description of option parameters

10.2.3 Case

10.2.4 gawk's built-in variables

10.2.5 Case

11. Summary


1. Getting Started with Shell Script

Shell scripts generally start with  #!/bin/bash    (specify parser)

And the general script files are suffixed with  .sh by default   (everyone uses it like this)

#   is its comment symbol;

As follows, write an output hello world! the script:

helloworld.sh 

#!/bin/bash

echo "hello world!"

 

1.1 Three execution methods of Shell script

1.1.1 bash script relative path or absolute path or sh script relative path or absolute path

For example:

absolute path to bash + script

ygt@YGT:~/share/knowledge$ bash /home/ygt/share/knowledge/Shell/helloworld.sh
hello world!
ygt@YGT:~/share/knowledge$

bash + relative paths to scripts

ygt@YGT:~/share/knowledge/Shell$ bash ./helloworld.sh
hello world!
ygt@YGT:~/share/knowledge/Shell$

sh + absolute path to the script

ygt@YGT:~/share/knowledge/Shell$ sh /home/ygt/share/knowledge/Shell/helloworld.sh
hello world!
ygt@YGT:~/share/knowledge/Shell$

sh + relative path to the script

ygt@YGT:~/share/knowledge/Shell$ sh ./helloworld.sh
hello world!
ygt@YGT:~/share/knowledge/Shell$

1.1.2 Directly enter the absolute path or relative path of the script to execute the script (in this way, the script must have the execution permission 'x')

Give the script execution permission: chmod +x helloworld.sh

Execute the script relative to the path:

ygt@YGT:~/share/knowledge/Shell$ ./helloworld.sh
hello world!
ygt@YGT:~/share/knowledge/Shell$

Absolute path execution script:

ygt@YGT:~/share/knowledge/Shell$ /home/ygt/share/knowledge/Shell/helloworld.sh
hello world!
ygt@YGT:~/share/knowledge/Shell$

Note : The first way to execute the script, the essence is that the bash parser helps you execute the script, so the script itself can be executed without the execution permission 'x'; the second way to execute the script, the essence is that the script executes itself, so it needs to be executed Permission 'x'.

3. Use '.' or source

with the first way type

ygt@YGT:~/share/knowledge/Shell$ . helloworld.sh
hello world!
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ source helloworld.sh
hello world!
ygt@YGT:~/share/knowledge/Shell$

Note : The first method and the second method both open a sub-shell in the current shell to execute the script content. When the script content ends, the sub-shell closes and returns to the parent shell; the third method is in the current shell Execute scripts without opening a subshell.

The difference between opening a sub-shell and not opening a sub-shell is that the inheritance relationship of environment variables, such as the current variable set in the sub-shell, is invisible to the parent shell.


2. Variables

Variables are divided into local variables and global variables. Local variables can only be used in this shell, while global variables can be used in this shell or its sub-shells. (The system predefined variables are global variables, and the customized ones are local variables) 

2.1 System predefined variables

Commonly used system variables: $HOME, $PWD, $SHELL, $USER

You can use echo or printenv to print out the value in the variable

ygt@YGT:~/share/knowledge/Shell$ printenv HOME
/home/ygt
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ echo $HOME
/home/ygt
ygt@YGT:~/share/knowledge/Shell$

You can use  set    to view all variables in the current shell;

2.2 Custom variables

2.2.1 Basic syntax

  • Define variables: variable name = variable value        Note that there must be no spaces before and after the = sign
  • Unset variable: unset variable name
  • Declare a static variable (constant): readonly variable name = variable value        Note, cannot unset

2.2.2 Variable definition rules

  • The variable name can be composed of letters, numbers and underscores, but cannot start with a number, and the environment variable name is recommended to be capitalized;
  • There cannot be spaces on both sides of the equal sign;
  • In bash, the default type of variables is string type, which cannot be directly operated by value;
  • If the value of the variable has spaces, it needs to be enclosed in double quotes or single quotes.

2.2.3 Case

        2.2.3.1 Define variable name

ygt@YGT:~/share/knowledge/Shell$ name=hello
ygt@YGT:~/share/knowledge/Shell$ echo $name
hello
ygt@YGT:~/share/knowledge/Shell$

        2.2.3.2 Reassign the variable name

ygt@YGT:~/share/knowledge/Shell$ name=world
ygt@YGT:~/share/knowledge/Shell$ echo $name
world
ygt@YGT:~/share/knowledge/Shell$

        2.2.3.3 Undo variable name

ygt@YGT:~/share/knowledge/Shell$ unset name
ygt@YGT:~/share/knowledge/Shell$ echo $name

ygt@YGT:~/share/knowledge/Shell$

        2.2.3.4 Declare the static variable (constant) age, the static variable cannot be modified, nor can unset

ygt@YGT:~/share/knowledge/Shell$ readonly age=24
ygt@YGT:~/share/knowledge/Shell$ echo $age
24
ygt@YGT:~/share/knowledge/Shell$ age=25
-bash: age: 只读变量
ygt@YGT:~/share/knowledge/Shell$ unset age
-bash: unset: age: 无法取消设定: 只读 variable
ygt@YGT:~/share/knowledge/Shell$

        2.2.3.5 In bash, the default type of variables is string type, which cannot perform direct numerical operations

ygt@YGT:~/share/knowledge/Shell$ sum=1+2
ygt@YGT:~/share/knowledge/Shell$ echo $sum
1+2
ygt@YGT:~/share/knowledge/Shell$

        2.2.3.6 If the value of the variable has spaces, it needs to be enclosed in double quotes or single quotes

ygt@YGT:~/share/knowledge/Shell$ name="hello world!"
ygt@YGT:~/share/knowledge/Shell$ echo $name
hello world!
ygt@YGT:~/share/knowledge/Shell$

Note that all the variables created above are local variables, which can only be used in this shell!

        2.2.3.7 Promote local variables to global variables, which can be used by other shell programs

                export variable name

ygt@YGT:~/share/knowledge/Shell$ export sum

                Output the value of sum in the helloworld.sh file

ygt@YGT:~/share/knowledge/Shell$ vim helloworld.sh


#!/bin/bash
echo "hello world!"
echo $sum


ygt@YGT:~/share/knowledge/Shell$ ./helloworld.sh
hello world!
1+2

Note that modifying the global variables of the parent shell in the sub-shell can only see the effect in the sub-shell, but cannot affect the parent shell;

For example, modify the value of sum in the helloworld.sh file, then output to view the effect, execute the helloworld.sh script, and then execute echo $sum to view the value of sum

#!/bin/bash

echo "hello world!"
echo $sum
sum=100
echo $sum
ygt@YGT:~/share/knowledge/Shell$ ./helloworld.sh
hello world!
1+2
100
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ echo $sum
1+2
ygt@YGT:~/share/knowledge/Shell$

It can be seen that the value of sum has not been modified, it is still 1+2

But if you use '.' or source to execute the script, you can modify it normally!

ygt@YGT:~/share/knowledge/Shell$ . helloworld.sh
hello world!
1+2
100
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ echo $sum
100
ygt@YGT:~/share/knowledge/Shell$

If you want to add two numbers, you can use brackets ( ) or square brackets [ ]!

ygt@YGT:~/share/knowledge/Shell$ age=$((1+2))
ygt@YGT:~/share/knowledge/Shell$ echo $age
3
ygt@YGT:~/share/knowledge/Shell$ age=$[2+3]
ygt@YGT:~/share/knowledge/Shell$ echo $age
5
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ a=10
ygt@YGT:~/share/knowledge/Shell$ b=20
ygt@YGT:~/share/knowledge/Shell$ age=$[a+b]
ygt@YGT:~/share/knowledge/Shell$ echo $age
30
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ age=$[a+10]
ygt@YGT:~/share/knowledge/Shell$ echo $age
20
ygt@YGT:~/share/knowledge/Shell$

2.3 Special variables

a = 10 

Note that if you wrap the variable $a with single quotes ' ', the shell will parse it into a string $a; if you wrap the variable $a with double quotes " ", the shell will parse it into a variable $a, that is, Get the value 10.

2.3.1 $n

        $n (function description: n is a number, $0 represents the name of the script, $1-$9 represents the first to ninth parameters, and more than ten parameters need to be enclosed in braces, such as ${10}, ${11}, etc.)

example:

Write a script with the following content:

#!/bin/bash

echo '以下为$n的用法'
echo "文件名:$0"
echo "第一个参数:$1"
echo "第二个参数:$2"
echo "第三个参数:$3"
ygt@YGT:~/share/knowledge/Shell$ ./special.sh one 二 3
以下为$n的用法
文件名:./special.sh
第一个参数:one
第二个参数:二
第三个参数:3
ygt@YGT:~/share/knowledge/Shell$

2.3.2 $#

$# (Function description: Get the number of all input parameters, often used in loops, to judge whether the number of parameters is correct and to strengthen the robustness of the script)

example:

Write a script with the following content:

#!/bin/bash

echo "参数个数:$#"
ygt@YGT:~/share/knowledge/Shell$ ./special.sh one 二 3
参数个数:3
ygt@YGT:~/share/knowledge/Shell$

2.3.3 $*

$* (Function description: this variable represents all the parameters in the command line, $* regards all parameters as a whole )

example:

Write a script with the following content:

#!/bin/bash

echo '输出$*:'
echo $*
ygt@YGT:~/share/knowledge/Shell$ ./special.sh one 二 3
输出$*:
one 二 3
ygt@YGT:~/share/knowledge/Shell$

2.3.4 $@

$@ (Function description: This variable represents all parameters in the command line, but $@ treats each parameter differently )

That is, what $@ gets is the list that stores all the parameters, or the array that stores all the parameters, you can use the for loop to traverse one by one to get them out (we will talk about how to traverse later)

example:

Write a script with the following content:

#!/bin/bash

echo '输出$@'
echo $@
ygt@YGT:~/share/knowledge/Shell$ ./special.sh one 二 3
输出$@
one 二 3
ygt@YGT:~/share/knowledge/Shell$

2.3.5 $?

$? (Function description: the return status of the last executed command. If the value of this variable is 0, it proves that the previous command was executed correctly; if the value of this variable is not 0 (the specific number is determined by the command itself), then Prove that the previous command was executed incorrectly)

example:

Determine whether the helloworld.sh script is executed successfully 

root@YGT:/home/ygt/share/knowledge/Shell# ./helloworld.sh
hello world!

100
root@YGT:/home/ygt/share/knowledge/Shell# echo $?
0
root@YGT:/home/ygt/share/knowledge/Shell#
root@YGT:/home/ygt/share/knowledge/Shell# ./helloworld1.sh
bash: ./helloworld1.sh: 没有那个文件或目录
root@YGT:/home/ygt/share/knowledge/Shell# echo $?
127
root@YGT:/home/ygt/share/knowledge/Shell#

3. Operators

From the above, we know that Shell cannot directly perform calculations. For example, a=1+2 outputs the result of traversing a is 1+2;

Shell has two ways to run: "$((compression expression))" or "$[compression expression]"

example: 

root@YGT:/home/ygt/share/knowledge/Shell# a=$((10 + 20))
root@YGT:/home/ygt/share/knowledge/Shell# echo $a
30
root@YGT:/home/ygt/share/knowledge/Shell# a=$[10*20]
root@YGT:/home/ygt/share/knowledge/Shell# echo $a
200
root@YGT:/home/ygt/share/knowledge/Shell#
root@YGT:/home/ygt/share/knowledge/Shell# a=10
root@YGT:/home/ygt/share/knowledge/Shell# b=20
root@YGT:/home/ygt/share/knowledge/Shell#
root@YGT:/home/ygt/share/knowledge/Shell# c=$(($a + $b))
root@YGT:/home/ygt/share/knowledge/Shell# echo $c
30
root@YGT:/home/ygt/share/knowledge/Shell# a=$[$b + $c]
root@YGT:/home/ygt/share/knowledge/Shell# echo $a
50
root@YGT:/home/ygt/share/knowledge/Shell#

Or c=$((a + b)) a=$[b + c] This is also possible!

Case, create a new add.sh file, input two numbers as parameters, and output after adding

#!/bin/bash

sum=$[$1+$2]

echo sum=$sum
root@YGT:/home/ygt/share/knowledge/Shell# ./add.sh 10 20
sum=30
root@YGT:/home/ygt/share/knowledge/Shell#

4. Condition judgment

4.1 Basic syntax

        (1). Test conditions        

        (2). [Condition] (Note that there must be spaces before and after the condition)

        ( After the comparison is complete, use $? to view the result, 0 means match (true), 1 means no match (false) )

 

4.2 Common Judgment Conditions

        4.2.1 Comparison between strings        

                (Note: If it is a comparison between strings, use the equal sign "=" to judge equality; use "!=" to judge unequal.)

                4.2.1.1   = equal to

ygt@YGT:~/share/knowledge/Shell$ a=hello
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ test $a = hello    # 注意,等号两边需要有空格
ygt@YGT:~/share/knowledge/Shell$ echo $?
0
ygt@YGT:~/share/knowledge/Shell$ test $a = Hello    # 注意,等号两边需要有空格
ygt@YGT:~/share/knowledge/Shell$ echo $?
1
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ a=hello
ygt@YGT:~/share/knowledge/Shell$ b=world
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ [ $a = $b ]    # 注意,[ ] 内部也需要有空格与条件分割
ygt@YGT:~/share/knowledge/Shell$ echo $?
1
ygt@YGT:~/share/knowledge/Shell$ b=hello
ygt@YGT:~/share/knowledge/Shell$ [ $a = $b ]    # 注意,[ ] 内部也需要有空格与条件分割
ygt@YGT:~/share/knowledge/Shell$ echo $?
0
ygt@YGT:~/share/knowledge/Shell$

        Note that if there are no spaces on both sides of the equal sign, the shell will parse it into a value, so the result will be 0 (true); when there is nothing in the condition, the result will be 1 (false), as follows:

ygt@YGT:~/share/knowledge/Shell$ a=hello
ygt@YGT:~/share/knowledge/Shell$ test $a=Hello
ygt@YGT:~/share/knowledge/Shell$ echo $?
0
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ a=hello
ygt@YGT:~/share/knowledge/Shell$ [ $a=hello ]
ygt@YGT:~/share/knowledge/Shell$ echo $?
0
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ [ sdfjogwoegjowg ]
ygt@YGT:~/share/knowledge/Shell$ echo $?
0
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ [ ]
ygt@YGT:~/share/knowledge/Shell$ echo $?
1
ygt@YGT:~/share/knowledge/Shell$

               4.2.1.2   != not equal to

ygt@YGT:~/share/knowledge/Shell$ a=hello
ygt@YGT:~/share/knowledge/Shell$ [ $a != hello ]
ygt@YGT:~/share/knowledge/Shell$ echo $?
1
ygt@YGT:~/share/knowledge/Shell$ [ $a != Hello ]
ygt@YGT:~/share/knowledge/Shell$ echo $?
0
ygt@YGT:~/share/knowledge/Shell$

         4.2.2  Comparison between integers

-eq equal to (equal)
- is not equal
-lt less than (less than)
- the Less than or equal to (less equal)
-gt greater than
-ge greater than or equal to
ygt@YGT:~$ a=10
ygt@YGT:~$ b=20
ygt@YGT:~$ [ $a -eq $b ]        # 判断10是否等于20
ygt@YGT:~$ echo $?
1
ygt@YGT:~$ [ $a -lt $b ]        # 判断10是否小于20
ygt@YGT:~$ echo $?
0
ygt@YGT:~$ [ 10 -ge 10 ]        # 判断10是否大于等于10
ygt@YGT:~$ echo $?
0
ygt@YGT:~$

        4.2.3 Judging by file permissions

-r Determine whether the file has read permission (read)
-w Determine whether the file has write permission (write)
-x Determine whether the file has execution permission (execute)
ygt@YGT:~$ touch test.txt
ygt@YGT:~$ ll
总用量 1
drwxr-xr-x 9 ygt  ygt      4096  6月  5 23:07 ./
drwxr-xr-x 3 root root     4096 11月 16  2022 ../
-rw-rw-r-- 1 ygt  ygt         0  6月  5 23:07 test.txt
ygt@YGT:~$
ygt@YGT:~$ [ -r test.txt ]        # 判断test.txt文件是否有读的权限
ygt@YGT:~$ echo $?
0
ygt@YGT:~$ [ -x test.txt ]        # 判断test.txt文件是否有执行的权限
ygt@YGT:~$ echo $?
1
ygt@YGT:~$

       4.2.4 Judging by file type

-e Determine whether the file exists (existence)
-f Determine whether the file exists and is a regular file (file)
-d Determine whether the file exists and is a directory (directory)
ygt@YGT:~$ ll
总用量 2
drwxr-xr-x 10 ygt  ygt      4096  6月  5 23:17 ./
drwxr-xr-x  3 root root     4096 11月 16  2022 ../
drwxrwxr-x  2 ygt  ygt      4096  6月  5 23:17 test/
-rw-rw-r--  1 ygt  ygt         0  6月  5 23:07 test.txt
ygt@YGT:~$
ygt@YGT:~$ [ -e test.txt ]
ygt@YGT:~$ echo $?
0
ygt@YGT:~$ [ -e test ]
ygt@YGT:~$ echo $?
0
ygt@YGT:~$ [ -f test ]
ygt@YGT:~$ echo $?
1
ygt@YGT:~$ [ -d test ]
ygt@YGT:~$ echo $?
0
ygt@YGT:~$ [ -f test.txt ]
ygt@YGT:~$ echo $?
0
ygt@YGT:~$

 

4.3 Multi-condition judgment && || 

Multi-condition judgment (&& indicates that the next command will be executed only when the previous command is successfully executed; || indicates that the next command will be executed only after the previous command fails)

Can also be used for short-circuit execution!

ygt@YGT:~$ a=10
ygt@YGT:~$ [ $a -gt 5 ] && echo "$a > 5"
10 > 5
ygt@YGT:~$ [ $a -lt 5 ] || echo "$a 不小于 5"
10 不小于 5
ygt@YGT:~$
ygt@YGT:~$ [ $a -lt 20 ] && echo "$a < 20" || echo "$a >= 20"
10 < 20
ygt@YGT:~$
ygt@YGT:~$ a=30
ygt@YGT:~$ [ $a -lt 20 ] && echo "$a < 20" || echo "$a >= 20"
30 >= 20
ygt@YGT:~$

Can also be used in commands!

ygt@YGT:~$ ls || ll
5       test          test.txt
ygt@YGT:~$

When the ls command is executed successfully, the subsequent ll command will not be executed!


5. Process control

Flow control is very important in any program, such as if, case, for, while;

5.1 if judgment

5.1.1 Single branch

if [ 条件判断式 ]; then    # 注意,这里的 ; 是有的
程序
fi

或者

if [ 条件判断式 ]
then
程序
fi

Create a new file and write the following content: (Input an integer to determine whether it is less than 10)

#!/bin/bash

if [ $1 -lt 10 ]; then
        echo "$1 < 10"
fi

if [ "$2"x = "abc"x ]    # 特殊用法,即使没有参数2,也可以正常运行
then
        echo "相等"
fi
ygt@YGT:~/share/knowledge/Shell$ ./process.sh 5
5 < 10

Of course, you can also use && or || to judge multiple conditions;

ygt@YGT:~/share/knowledge/Shell$ a=20
ygt@YGT:~/share/knowledge/Shell$ if [ $a -gt 18 ] && [ $a -lt 40 ]; then echo OK; fi
OK

&& and || can be replaced by -a and -o , and then the condition can be written in a []; (-a is equal to and -o is equal to or) 

ygt@YGT:~/share/knowledge/Shell$ a=20
ygt@YGT:~/share/knowledge/Shell$ if [ $a -gt 18 -a $a -lt 40 ]; then echo OK; fi
OK

5.1.2 Multi-branch

if [ 条件判断式 ]; then
程序
elif [ 条件判断式 ]; then
程序
else
程序
fi

Create a new file with the following content: 

#!/bin/bash

if [ $1 -lt 18 ]; then
	echo "未成年"
else
	echo "已成年"
fi


if [ $2 -ge 0 -a $2 -lt 60 ]; then
	echo "不及格"
elif [ $2 -ge 60 -a $2 -le 90 ]; then
	echo "及格"
elif [ $2 -gt 90 -a $2 -le 100 ]; then
	echo "优秀"
else
	echo  "成绩有误"
fi
[centos7@localhost Shell]$ ./process.sh 24 70
已成年
及格
[centos7@localhost Shell]$ ./process.sh 16 -1
未成年
成绩有误
[centos7@localhost Shell]$ 

5.1.3 Use of (( )) in if

Use (( )) to use C-like usage in parentheses; of course, it is generally not recommended to use this way!

ygt@YGT:~/share/knowledge/Shell$ a=10
ygt@YGT:~/share/knowledge/Shell$ if (( $a > 20 )); then echo OK; else echo notOK; fi
notOK

5.2 case statement

5.2.1 Basic syntax

case $变量名 in
"值 1")
如果变量的值等于值 1,则执行程序 1
;;
"值 2")
如果变量的值等于值 2,则执行程序 2
;;
*)
如果变量的值都不是以上的值,则执行此程序(defualt)
;;
esac

Precautions:

  • The case line must end with the word "in", and each pattern match must end with a closing bracket ")";
  • The double semicolon ";;" indicates the end of the command sequence, which is equivalent to break in C/C++;
  • The last "*)" indicates the default mode, which is equivalent to default in C/C++;

Mainly note that the above syntax is different, and other usages are consistent with C/C++ switch case usage.

5.2.2 Case

Create a new file with the following content: 

#!/bin/bash

case $1 in
"1")
	echo "one"
;;
"2")	
    echo "two"
;;
"3")	
    echo "three"
;;
*)
	echo "other"
;;
esac
[centos7@localhost Shell]$ ./process_case.sh 2
two

 

5.3 for loop

There are two types of for loops, for and for in

5.3.1  for

 Use (( )) to use C-like usage in parentheses; for loops can be used like this!

for (( 初始值; 循环控制条件; 变量变化 ))
do
程序
done

Create a new file and write the following: (calculate 1+...+n)

#!/bin/bash

sum=0

for (( i=1; i <= $1; i++ )); do
        sum=$[ $sum + $i ]
        #sum=$[ sum + i ]    # 貌似这样写也是可以的
        #sum=$((sum + i))    # 貌似这样写也是可以的  
        #let sum=sum+i 
done

echo "sum = $sum"

Note that with the update of the Linux Shell, the let keyword can be used    to implement the current high-level language usage

For example: let sum=sum+i let sum++ etc.

ygt@YGT:~/share/knowledge/Shell$ ./sum.sh 10
sum = 55

5.3.2 for in (enhance the for loop, use a little more)

for 变量 in 值 1 值 2 值 3…
do
程序    # 变量 的取值为 in 后面的值
done
#!/bin/bash

for os in Linux Windows Macos; do
        echo $os;
done
ygt@YGT:~/share/knowledge/Shell$ ./sum.sh
Linux
Windows
Macos
ygt@YGT:~/share/knowledge/Shell$

Of course, you can also give him a collection after in, wrapped with { .. }, for example:

ygt@YGT:~/share/knowledge/Shell$ for i in {1..100}; do sum=$[ $sum + $i ]; done; echo "sum = $sum"
sum = 5050
ygt@YGT:~/share/knowledge/Shell$

5.3.3 Difference between $* and $@

Both $* and $@ represent all the parameters passed to the function or script, and when they are not included by double quotes "", all parameters are output in the form of $1 $2 ... $n. 

 $*: Treat parameters as a whole;

$@: treat the parameters as an independent individual

Create a new file with the following content:

(If $* and $@ in the code are not enclosed in double quotes, they will achieve the same effect, and you will not be able to see the difference)

#!/bin/bash

echo '$*:'
for pro in "$*"; do     # 注意这里$*一定要用双引号括起来,就可以看出其将参数看作是一个整体
        echo $pro
done

echo '$@:'
for pro in "$@"; do     # 注意这里$@一定要用双引号括起来,就可以看出其将参数看作是分开的独立个体
        echo $pro
done
ygt@YGT:~/share/knowledge/Shell$ ./process_for.sh 1 2 3 a b c
$*:
1 2 3 a b c
$@:
1
2
3
a
b
c
ygt@YGT:~/share/knowledge/Shell$

$* regards the parameter as a string as a whole, while $@ regards the parameter as an independent individual

5.4 while loop

while [ 条件判断式 ]
do
程序
done
#!/bin/bash

i=1
sum=0

#while (( i <= $1 )); do        # 也可以使用 (( )) 替代[ ]
while [ $i -le $1 ]; do
        sum=$[ $sum + $i ]
        i=$[ $i + 1 ]
        #let sum=sum+i
        #let i++
done

echo "sum = $sum"

(You can use the let keyword to modify the usage of the high-level language!) 

In the code, both (( )) and [ ] can be used interchangeably!

Generally while is used []

ygt@YGT:~/share/knowledge/Shell$ ./process_while.sh 100
sum = 5050

6. read read console input

read (option) (argument)

①Options:

        -p: Specify the prompt when reading the value;

        -t: Specify the waiting time (seconds) when reading the value. If -t is not added, it means waiting all the time

                (After the -t time is added, the read operation will end and continue to execute)

② parameters

        Variable: Specify the variable name to read the value from

Create a new file with the following content: 

#!/bin/bash

read -t 7 -p "请输入您的名字:" name

#if [ "$name" == "" ]; then
if [ ! $name ]; then
        echo "Name is NULL"
else
        echo "Your name is $name"
fi
ygt@YGT:~/share/knowledge/Shell$ ./process_read.sh
请输入您的名字:李华
Your name is 李华
ygt@YGT:~/share/knowledge/Shell$ ./process_read.sh
请输入您的名字:Name is NULL
ygt@YGT:~/share/knowledge/Shell$

Seven, function

Small case, splice file name (date function), the format is: file name_log_timestamp

#!/bin/bash

filename="$1"_log_$(date +%s)
echo $filename

date is a system function, +%s is the parameter passed in to it, so as to get the timestamp and return 

ygt@YGT:~/share/knowledge/Shell$ ./date.sh test
test_log_1686280637
ygt@YGT:~/share/knowledge/Shell$

How to call a system function: $(system function) aka: command substitution

 

7.1 System functions

Here are two commonly used system functions, basename and dirname;

7.1.1 basename

        7.1.1.1 Basic syntax

                basename [string / pathname] [suffix]

                (Function description: The basename command will delete all prefixes including the last ('/') character, and then display the string.

                basename can be understood as taking the file name in the path

                Options: suffix is ​​the suffix, if suffix is ​​specified, basename will remove the suffix in pathname or string.

Note that basename can only intercept strings with /!

        7.1.1.2 Case

ygt@YGT:~/share/knowledge/Shell$ basename /home/ygt/share/knowledge/Shell/date.sh
date.sh
ygt@YGT:~/share/knowledge/Shell$ basename /home/ygt/share/knowledge/Shell/date.sh .sh
date
ygt@YGT:~/share/knowledge/Shell$ basename ./date.sh
date.sh
ygt@YGT:~/share/knowledge/Shell$ basename /abcsdf/asdgwr/erg43
erg43

7.1.2 address

        7.1.2.1 Basic syntax

                dirname file absolute path

                 (Function description: Remove the file name (non-directory part) from the given file name containing the absolute path, and then return the remaining path (directory part))

                 dirname can be understood as the absolute path name of the file path

       7.1.2.2 Case

ygt@YGT:~/share/knowledge/Shell$ dirname /home/ygt/share/knowledge/Shell/date.sh
/home/ygt/share/knowledge/Shell
ygt@YGT:~/share/knowledge/Shell$ dirname ./date.sh
.
ygt@YGT:~/share/knowledge/Shell$ dirname /sadfsg/gwgwrga/agwgg
/sadfsg/gwgwrga

There is also a more interesting way to call the script in any path, and output the full path where the script is located:

#!/bin/bash

echo $(cd $(dirname $0); pwd)
ygt@YGT:~/share/knowledge/Shell$ ./date.sh
/home/ygt/share/knowledge/Shell

ygt@YGT:~/share/knowledge/Shell$ cd /
ygt@YGT:/$ /home/ygt/share/knowledge/Shell/date.sh
/home/ygt/share/knowledge/Shell

ygt@YGT:/$ cd /home/ygt/share/knowledge/shared_bike/src/
ygt@YGT:~/share/knowledge/shared_bike/src$ ../../Shell/date.sh
/home/ygt/share/knowledge/Shell

 

7.2 Custom functions

7.2.1 Basic syntax

[ function ] funname [()]
{
    Action;
    [return int;]
}

7.2.2 Precautions

  • The function must be declared before calling the function, and the shell script is run line by line. Does not compile first like other languages;
  • The return value of the function can only be obtained through the $? system variable, which can be displayed and added: return return, if not added, the result of the last command will be used as the return value. return followed by the value n(0-255);
  • Because the return value obtained through $? can only be between 0-255; so you can use echo to output the data, and then use $() to call the function, you can get the result of the echo output, that is, the return value of the function;
  • There is no need to specify parameters when defining a function, and the parameters are passed directly when calling the function, and $1, $2...$n are used inside the function to obtain parameter values! 

7.2.3 Case

Create a new file with the following content:

#!/bin/bash

function add() {
        s=$[ $1 + $2 ]
        return $s       # 注意,只能返回0-255之间的数
}

read -p "请输入第一个整数:" a
read -p "请输入第二个整数:" b

add $a $b
echo "$a + $b = $?"
ygt@YGT:~/share/knowledge/Shell$ ./func.sh
请输入第一个整数:10
请输入第二个整数:20
10 + 20 = 30
ygt@YGT:~/share/knowledge/Shell$ ./func.sh
请输入第一个整数:100
请输入第二个整数:200
100 + 200 = 44
ygt@YGT:~/share/knowledge/Shell$

Because $? can only get the value between 0-255, so when it exceeds, the correct value cannot be returned;

In order to solve such a problem, you can use echo to output the value, and then use $() to call the function to receive it; as follows:

#!/bin/bash

function add() {
        s=$[ $1 + $2 ]    # s=$(( $1 + $2 ))
        echo $s
}

read -p "请输入第一个整数:" a
read -p "请输入第二个整数:" b

sum=$( add $a $b )
echo "$a + $b = $sum"
ygt@YGT:~/share/knowledge/Shell$ ./func.sh
请输入第一个整数:100
请输入第二个整数:200
100 + 200 = 300

Note that if there are multiple echo outputs in the function, only the value of the last echo output can be obtained at the place where the function is called!


8. Comprehensive application - realize file archiving

This is a comprehensive application of the knowledge points in the first seven chapters above to realize the file archiving operation!

In actual production applications, it is often necessary to archive and backup important data;

Requirement: Implement a script that archives and backs up the specified directory every day, enter a directory name (without / at the end), archive and save all files in the directory by day, and append the archive date to the archive file name, and put it in /hong/ ygt down;

The archive command is used here: tar

The -c option can be added later to indicate archiving, and the -z option can be added to indicate simultaneous compression, and the resulting file extension is .tar.gz.

The script is implemented as follows:

#!/bin/bash

# 首先判断输入的参数个数是否为1
if [ $# -ne 1 ]; then
        echo "参数个数错误!应输入一个参数,作为归档目录名"
        exit
fi

# 从参数中获取目录名称
if [ -d $1 ]; then
        echo
else
        echo
        echo "目录不存在!"
        echo
        exit
fi

DIR_NAME=$(basename $1)
DIR_PATH=$(cd $(dirname $1); pwd)

# 获取当前日期
DATE=$(date +%y%m%d)

# 定义生成的归档文件名
FILE=Shell_${DIR_NAME}_${DATE}.tar.gz
DEST=/home/ygt/$FILE

# 开始归档目录文件
echo "开始归档..."
echo

tar -zcf $DEST $DIR_PATH/$DIR_NAME

if [ $? -eq 0 ]; then
        echo
        echo "归档成功!"
        echo "归档文件为:$DEST"
        echo
else
        echo "归档失败!"
        echo
fi


9. Getting Started with Regular Expressions

Regular expressions use a single string to describe and match a series of strings that meet a certain grammatical rule. In many text editors, regular expressions are usually used to retrieve and replace text that matches a certain pattern. In Linux, text processing tools such as grep, sed, and awk all support pattern matching through regular expressions.

 

9.1 Regular matching

A string of regular expressions that contain no special characters matches itself, for example:

ygt@YGT:~/share/knowledge/Shell$ cat archive.sh | grep DATE
DATE=$(date +%y%m%d)
FILE=Shell_${DIR_NAME}_${DATE}.tar.gz

You can match the row containing DATE!

 

9.2 Commonly used special characters

9.2.1    ^

^   matches the beginning of a line, for example:

ygt@YGT:~/share/knowledge/Shell$ cat archive.sh | grep ^i
if [ $# -ne 1 ]; then
if [ -d $1 ]; then
if [ $? -eq 0 ]; then
ygt@YGT:~/share/knowledge/Shell$

9.2.2    $

$   matches the end of a line, for example:

ygt@YGT:~/share/knowledge/Shell$ cat archive.sh | grep gz$
FILE=Shell_${DIR_NAME}_${DATE}.tar.gz
ygt@YGT:~/share/knowledge/Shell$

9.2.3   .

.   matches an arbitrary character, for example:

ygt@YGT:~/share/knowledge/Shell$ cat archive.sh | grep h.me
DEST=/home/ygt/$FILE
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ cat archive.sh | grep h...
if [ $# -ne 1 ]; then
        echo "参数个数错误!应输入一个参数,作为归档目录名"
        echo "目录不存在!"
FILE=Shell_${DIR_NAME}_${DATE}.tar.gz
DEST=/home/ygt/$FILE
echo "开始归档..."
        echo "归档成功!"
        echo "归档文件为:$DEST"
        echo "归档失败!"
ygt@YGT:~/share/knowledge/Shell$

9.2.4   *

* is not used alone, it is used together with the previous character, which means matching the previous character 0 or more times, for example:

ygt@YGT:~/share/knowledge/Shell$ cat /etc/passwd | grep ro*t
root:x:0:0:root:/root:/bin/bash
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
ygt@YGT:~/share/knowledge/Shell$

will match all lines such as rt, rot, root, rooot, roooot, etc.

There is also +   , which matches 1 or n times; ? Matches 0 or 1 times!

In addition: .*   used in combination means, match any number of arbitrary characters!

9.2.5 Character range (brackets): [ ]

[ ] means match a character within a certain range, for example:

        [6,8] —— match 6 or 8 [0-9]------match a number of 0-9;

        [0-9]* —— match a string of numbers of any length;

        [az] - match a character between az;

        [az]* —— matches an alphabetic string of any length;

        [ac, ef] - match any character between ac or ef;

ygt@YGT:~/share/knowledge/Shell$ echo "541rooabcbbat" | grep r[o,a,b,c]*t
541rooabcbbat
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ cat /etc/passwd | grep r[a-z]*t
root:x:0:0:root:/root:/bin/bash
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
ygt@YGT:~/share/knowledge/Shell$

9.2.6   \

means escape and will not be used alone. Since all special characters have their specific matching pattern, when we want to match a special character itself (for example, I want to find all lines containing '$'), we will encounter difficulties. At this point, we need to use escape characters and special characters together to represent the special characters themselves, for example:

ygt@YGT:~/share/knowledge/Shell$ cat archive.sh | grep '\$'
if [ $# -ne 1 ]; then
if [ -d $1 ]; then
DIR_NAME=$(basename $1)
DIR_PATH=$(cd $(dirname $1); pwd)
DATE=$(date +%y%m%d)
FILE=Shell_${DIR_NAME}_${DATE}.tar.gz
DEST=/home/ygt/$FILE
tar -zcf $DEST $DIR_PATH/$DIR_NAME
if [ $? -eq 0 ]; then
        echo "归档文件为:$DEST"
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ cat archive.sh | grep '/\$'
DEST=/home/ygt/$FILE
tar -zcf $DEST $DIR_PATH/$DIR_NAME
ygt@YGT:~/share/knowledge/Shell$

You can match the line containing $! You can match the line containing /$!

 

9.3 Exercise, matching mobile phone numbers

ygt@YGT:~/share/knowledge/Shell$ echo "15712345678" | grep ^1[3,4,5,7,8][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]&
ygt@YGT:~/share/knowledge/Shell$ 15712345678
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ echo "15712345678" | grep -E ^1[3,4,5,7,8][0-9]{9}&                                                                                                  
ygt@YGT:~/share/knowledge/Shell$ 15712345678

In addition, there are many other advanced usages of regular expressions, which have not been introduced here, and I will add them later when I have time to learn!


10. Text processing tools

10.1   cut

The job of cut is to "cut", specifically, it is responsible for cutting data in the file. The cut command cuts bytes, characters and fields from each line of the file and outputs these bytes, characters and fields;

10.1.1 Basic usage

        cut [option parameter] filename

        Description: The default delimiter is tab

10.1.2 Description of option parameters

option parameter Function
-f Column number, which column to extract
-d Delimiter, split columns according to the specified delimiter, the default is tab character "\t"
-c After cutting by character, add n to indicate which column to take, such as -c 1

10.1.3 Case

10.1.3.1 Prepare data

ygt@YGT:~/share/knowledge/Shell$ vim cut.txt
ygt@YGT:~/share/knowledge/Shell$ cat cut.txt
guang shen dong
zhou zhen guan
wo wo wo
lai lai lai
le le le

10.1.3.2 Split by space to get the first column

ygt@YGT:~/share/knowledge/Shell$ cut -d " " -f 1 cut.txt
guang
zhou
wo
lai
le

10.1.3.3 Split by spaces to get the second and third columns

ygt@YGT:~/share/knowledge/Shell$ cut -d " " -f 2,3 cut.txt
shen dong
zhen guan
wo wo
lai lai
le le

10.1.3.4 Cut out guang in the cut.txt file

ygt@YGT:~/share/knowledge/Shell$ cat cut.txt | grep guang | cut -d " " -f 1
guang

10.1.3.5 Cut out the user, path and bash of the /etc/passwd file

ygt@YGT:~/share/knowledge/Shell$ cat /etc/passwd | grep bash$
root:x:0:0:root:/root:/bin/bash
ygt:x:1000:1000:ygt,,,:/home/ygt:/bin/bash
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ cat /etc/passwd | grep bash$ | cut -d ":" -f 1,5,7
root:root:/bin/bash
ygt:ygt,,,:/bin/bash
ygt@YGT:~/share/knowledge/Shell$

10.1.3.6 Intercepting a range of columns

cat /etc/passwd | grep bash$ | cut -d ":" -f 2-4
cat /etc/passwd | grep bash$ | cut -d ":" -f -4
cat /etc/passwd | grep bash$ | cut -d ":" -f 3-

10.1.3.7 Intercept ip address

ygt@YGT:~/share/knowledge/Shell$ ifconfig | grep "广播"
          inet 地址:192.168.160.128  广播:192.168.160.255  掩码:255.255.255.0
ygt@YGT:~/share/knowledge/Shell$
ygt@YGT:~/share/knowledge/Shell$ ifconfig | grep "广播" | cut -d " " -f 12 | cut -d ":" -f 2
192.168.160.128
ygt@YGT:~/share/knowledge/Shell$

 

10.2   gawk

A powerful text analysis tool that reads files line by line, slices each line with spaces as the default delimiter, and then analyzes the cut parts;

10.2.1 Basic usage

gawk [option parameter] '/pattern1/{action1} /pattern2/{action2}...' filename

pattern: Indicates what gawk is looking for in the data, which is the matching pattern;

action: A sequence of commands to execute when a match is found;

10.2.2 Description of option parameters

option parameter Function
-F specify the input file separator
-v Assign a value to a user-defined variable

10.2.3 Case

Note: only the lines that match the pattern will execute the action

10.2.3.1 Search the /etc/passwd file for all lines beginning with the root keyword, and output column 7 of the line

ygt@YGT:~$ cat /etc/passwd | gawk -F ":" '/^root/{print $7}'
/bin/bash

10.2.3.2 Search for all lines in the /etc/passwd file that start with the root keyword, and output the first and seventh columns of the line, separated by ","

ygt@YGT:~$ cat /etc/passwd | gawk -F ":" '/^root/{print $1","$7}'
root,/bin/bash

10.2.3.3 Only display the first and seventh columns of /etc/passwd, separated by commas, and add the column name user and shell in front of all lines, and add "end!!!" to the last line

ygt@YGT:~$ cat /etc/passwd | gawk -F ":" 'BEGIN{print "user, shell"}/bash$/{print $1","$7} END{print "end!!!"}'
user, shell
root,/bin/bash
ygt,/bin/bash
end!!!
ygt@YGT:~$

Note: BEGIN is executed before all data read rows; END is executed after all data is executed.

10.2.3.4 Increase the user id in the /etc/passwd file by 1 and output

cat /etc/passwd | gawk -F ":" '{print $3}'             # 这是没有+1的
cat /etc/passwd | gawk -v i=1 -F ":" '{print $3+i}'    # 这是有+1的

10.2.4 gawk's built-in variables

variable illustrate
FILENAME file name
NR Number of records read (line number)
NF The number of domains in the browse record (after cutting, the number of columns)

10.2.5 Case

10.2.5.1 Statistics /etc/passwd file name, line number of each line, number of columns of each line

ygt@YGT:~$ gawk -F : '{print "文件名:"FILENAME", 行号:"NR", 列号:"NF}' /etc/passwd
文件名:/etc/passwd, 行号:1, 列号:7
文件名:/etc/passwd, 行号:2, 列号:7
文件名:/etc/passwd, 行号:3, 列号:7
# 。。。中间省略。。。
文件名:/etc/passwd, 行号:24, 列号:7
文件名:/etc/passwd, 行号:25, 列号:7

10.2.5.2 Query the line number of the blank line in the output result of the ifconfig command

ygt@YGT:~$ ifconfig | gawk '/^$/ {print "空行:"NR}'
空行:9
空行:18
ygt@YGT:~$

11. Summary

So far, the basic introductory tutorial of Linux Shell is completed!

Although there is no great knowledge point, but after learning these, it is enough to cope with daily work!

In addition, this tutorial is learned from watching the video of "Silicon Valley" on Bilibili!

Guess you like

Origin blog.csdn.net/cpp_learner/article/details/131047527