Shang Silicon Valley-Shell

1. Shell overview

​ Shell is a command interpreter that receives application/user commands and then invokes the operating system kernel.

image-20220523094259783

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

  1. The shell parsers provided by Linux are
cat /etc/shells
  1. The relationship between bash and sh
cd /bin
ll | grep bash

[root@lys bin]# echo $SHELL
/bin/bash

2. Getting Started with Shell Scripting

(1) Script format

​ The script starts with #!/bin/bash (specify parser)

(2) The first shell script helloworld.sh

touch helloworld.sh
vim helloworld.sh

# 内容
# !/bin/bash
echo "hellow world"

(3) Common execution methods of scripts

  1. bash or sh + the relative path or absolute path of the script (no need to give the script +x permission) (restart a process to execute the bash command)
sh ./helloworld.sh
bash ./helloworld.sh
  1. Use the absolute path or relative path of the input script to execute the script (must have executable permission + x) (essentially use the current bash process to execute the command)
./helloworld.sh
  1. [Understand] Add "." or source before the path of the script
source helloworld.sh 
. helloworld.sh

reason:

​ The first two methods are to find the one in the current shell to open a subshell to execute the script content. When the script content ends, the subshell relationship returns to the parent shell.

​ The third method, which is to add "." or source before the script path, can make the script content executed in the current shell without opening a subshell. This is why we need to source it every time we modify the /etc/profile file.

​ The difference between opening a subshell and not opening a subshell is that the integration relationship of environment variables, such as the current variable set in the subshell, is not visible to the parent shell.

child shell

[root@lys shell]# ps -f
UID        PID  PPID  C STIME TTY          TIME CMD
root      1907 10679  0 12:46 pts/1    00:00:00 ps -f
root     10679 10672  0 09:47 pts/1    00:00:00 -bash
[root@lys shell]# bash
[root@lys shell]# ps -f
UID        PID  PPID  C STIME TTY          TIME CMD
root      1970 10679  0 12:46 pts/1    00:00:00 bash
root      2006  1970  0 12:46 pts/1    00:00:00 ps -f
root     10679 10672  0 09:47 pts/1    00:00:00 -bash
[root@lys shell]# exit
exit
[root@lys shell]# ps -f
UID        PID  PPID  C STIME TTY          TIME CMD
root      2034 10679  0 12:46 pts/1    00:00:00 ps -f
root     10679 10672  0 09:47 pts/1    00:00:00 -bash

3. Variables

3.1 System predefined variables

Common System Variables

H O M E 、 HOME、 HOMEPWD、 S H E L L 、 SHELL、 SHELLUSER

(1) View the value of the system variable

echo $HOME

(2) Display all variables in the current shell:

env
set # 包含所有系统自定义和用户自定义的变量 
printenv $USER
printenv USER

3.2 Custom variables

(1) Basic grammar

  1. Define variables: variable name = variable, note that there must be no spaces before and after =
  2. Undo variable: usset variable name
  3. Declare static variable: readonly variable, note: cannot unset

(2) Variable definition rules

  1. Variable names can be composed of letters, numbers and underscores, but cannot start with a number. It is recommended that the environment variable name be capitalized.
  2. There can be no spaces on either side of the equal sign
  3. In bash, the default type of variables is string type, and numerical operations cannot be performed.
  4. If the value of the variable has spaces, it needs to be enclosed in double quotes or single quotes.
[root@lys shell]# a=2
[root@lys shell]# echo $a
2
# 提升为全部变量
[root@lys shell]# export a

new_var='hello linux'
vim helloworld.sh
# 追加
echo $new_var

sh helloworld.sh
#发现没有值
# 使用一下命令就有值
. hellworld.sh
sourcce hellowrld.sh

calculate

a=$((1+5))
a=$[1+5]

Define a read-only variable

readonly=5f

undo variable

unset a

3.3 Special variables

3.3.1 $n

​ $nn is a number, $0 represents the name of the script, $1-9 represents the first to ninth parameters, and parameters above ten need to be marked with braces, such as 9 represents the first to ninth parameters, and parameters above ten It needs to be marked with braces, such as9 represents the first to ninth parameters, and more than ten parameters need to be marked with braces, such as {10}

vim helloworld.sh
echo "hello,$1"
# 执行
sh helloworld.sh a
# 输出
hello,a

Example 2

#!/bin/bash
echo '======$n====='
echo script name: $0
echo 1st paramater: $1
echo 2nd paramater: $2

[root@lys shell]#  sh parameter.sh 0 1 2
======$n=====
script name: parameter.sh
1st paramater: 0
2nd paramater: 1

# 获取调用文件名称
basename

3.3.2 $#

​ $# Get the number of all input parameters, often used in loops, to determine whether the number of parameters is correct and to enhance the robustness of the script

vim parameter.sh 
#!/bin/bash
echo '======$n====='
echo script name: $0
echo 1st paramater: $1
echo 2nd paramater: $2
echo '======$#====='
echo paramter numbers: $#


sh parameter.sh ab cd
# 结果
======$n=====
script name: parameter.sh
1st paramater: ab
2nd paramater: cd
======$#=====
paramter numbers: 2

3.3.3 ∗ 、 *、 @

​∗ This variable represents all the parameters in the command line, * This variable represents all the parameters in the command line,This variable represents all the parameters in the command line, *Treat all the parameters as a whole

​The @@ This variable also represents all the parameters in the command line, but @ treats each parameter differently

vim paramter.sh
#!/bin/bash
echo '======$n====='
echo script name: $0
echo 1st paramater: $1
echo 2nd paramater: $2
echo '======$#====='
echo paramter numbers: $#
echo $*
echo $@


[root@lys shell]# sh parameter.sh ab cd
======$n=====
script name: parameter.sh
1st paramater: ab
2nd paramater: cd
======$#=====
paramter numbers: 2
ab cd
ab cd

3.3.4 $?

$? 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 this variable is non-zero (the specific number is determined by the command itself), it proves that the previous command was executed incorrectly)

[root@lys shell]# ./helloworld.sh 
helloworld
hello,
[root@lys shell]# echo $?
0

# 如果错误执行,就非0
[root@lys shell]# $?
-bash: 0: command not found
[root@lys shell]# echo $?
127

4 operators

$((expression)) or $[expression]

Calculate (2+3)*4

[root@lys shell]# echo $[(2+3)*4]
20

expr uses

expr 1 + 2
3

# 乘法需转义
expr 5 \* 2
10

command substitution

[root@lys shell]# a=$(expr 2 + 2)
[root@lys shell]# echo $a
4


[root@lys shell]# a=`expr 5 + 2`
[root@lys shell]# echo $a
7

additive script

#!/bin/bash
sum=$[$1 + $2]
echo $sum          

5 condition judgment

basic grammar

​ test condition

​ [ condition] (Note that there must be spaces before and after the condition)

Note: The condition is true if it is not empty, [lys] returns true, [ ] returns false

Common Judgment Conditions

(1) Comparison between two integers

-eq equal to (equal)

-ne is not equal to (not equal)

-lt less than (less than)

-le less than or equal to (less equal)

-gt greater than (greater than)

-ge greater than or equal to (greater equal)

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

(2) Judge according to file permissions

-r has read permission (read)

-w has write permission (write)

-x has permission to execute (execute)

# 判断文件是否有可执行权限
[root@lys shell]# [ -x helloworld.sh ]
[root@lys shell]# echo $?
0
# 结果0代表有

(3) Judging by file type

-e file exists (existence)

-f file exists and is a regular file (file)

-d file exists and is a directory (directory)

Case Practice

(1) Whether 23 is greater than or equal to 22

$ [ 23 -ge 22 ]

(2) Determine whether the file has executable permissions

$ [ -x helloworld.sh ]

(3) Whether the file exists

$ [ -e helloworld.sh]

6 Process control

6.1 if judgment

(1) Single branch

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

or

if [ 条件判断式 ]
then 
	程序
fi
if [ "$1"x = "lys"x ]
then
        echo 'welcome, lys'
fi   
if [ $a -gt 18 -a $a -lt 35]; then echo OK; fi 
-a and
-o or

multi-branch

if [ 条件判断式 ]
then 
	程序
if [ $2 -lt 18 ]
then
        echo "未成年人"
elif [ $2 -lt 35 ]
then
        echo "中年人"
else
        echo "成年人"
fi

6.2 case statement

basic grammar

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

Precautions:

​ (1) The end of the case line must be the word "in", and each pattern match must end with brackets ")"

(2) The double semicolon ";;" indicates the end of the command sequence, which is equivalent to java's breakl

(3) The last "*)" indicates the default mode, which is equivalent to default in java

case $1 in
1)
        echo "one"
;;
2)
        echo "two"
;;
3)
        echo "three"
;;
*)
        echo "number else"
;;
esac

sh case_test.sh 1

6.3 for loop

basic grammar

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

for (( i=1; i <= $1 ; i++  ))
do
        sum=$[ $sum + $i ]

done;

echo $sum

 for os in linux windows macos; do echo $os; done
for i in {
    
    1..100}; do sum=$[$sum+$i]; done; echo $sum

for with ∗ and * andand @

echo '$#'
for para in $*
do
        echo $para
done


echo '$@'
for para in $@
do
        echo $para
done


[root@lys shell]# sh for_test2.sh 1 2 3 
$#
1
2
3
$@
1
2
3

If surrounded by quotes

echo '$#'
for para in "$*"
do
        echo $para
done


echo '$@'
for para in "$@"
do
        echo $para
done


[root@lys shell]# sh for_test2.sh 1 2 3 
$#
1 2 3
$@
1
2
3

6.4 while loop

while [ 条件判断式 ]
do 	
	程序
done

The while loop realizes 1+ 100

i=1
sum=0
while [ $i -le 100 ]
do
        sum=$[ $sum + $i ]
        i=$[$i + 1]
# 		let sum+=i
#		let i++ let 实现方式 
done;
echo $sum

7 read reads console input

basic grammar

​ read (options) (parameters)

-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

​ Parameters:

​ Variable: Specify the variable name to read the value

Case Practice

​ Prompt within 7 seconds, read the name entered by the console

read -t 10 -p "请输入您的名称:" name
echo "welcome $name"

8 functions

8.1 System functions

8.1.1 basename

​ basename [string/pathname] [suffix] 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.

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

basename basic usage

[root@lys shell]# basename helloworld.sh 
helloworld.sh

[root@lys shell]# basename helloworld.sh .sh
helloworld

8.1.2 address

​ dirname file absolute path Get 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

​ Get the directory name of hellowolrd.sh

[root@lys shell]# dirname /java-project/shell/helloworld.sh 
/java-project/shell

8.2 Custom functions

[function] funname[()]

{

Action;

​ [return int;]

}

Skills

​ (1) The function must be declared before calling the function, and the shell script is run line by line. Doesn't compile first like other languages.

​ (2) 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 debriefing n (0–255)

Calculate the sum of two numbers

function add(){
    
    
        s=$[$1+$2]
        echo "sum=$s"
}
read -p "请输入第一个整数" a
read -p "请输入第二个整数" b
add $a $b

use#? The maximum can only return 255

function add(){
    
    
        s=$[$1+$2]
        return $s
}
read -p "请输入第一个整数" a
read -p "请输入第二个整数" b
add $a $b
echo "sum="$?

Use $() to get the value

function add(){
    
    
        s=$[$1+$2]
        echo $s
}
read -p "请输入第一个整数" a
read -p "请输入第二个整数" b
sum=$(add $a $b)
echo "sum=$sum"

11 Comprehensive case

11.1 Archive files

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

​ Requirements: 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 /root /archive.

​ The archive command is used here: tar

​ You can add -c to indicate archiving. Adding the -z option means compressing at the same time, and the resulting file suffix is ​​tar.gz

​ Script implementation:

 #!/bin/bash


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

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

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


# 获取当前日期
DATE=$(date +%y%m%d)
# 生成的归档文件名称
FILE=archive_${DIR_NAME}_$DATE.tar.gz
DEST=/root/archive/$FILE

# 开始归档
echo "开始归档..."
echo 

tar -zcf $DEST  $DIR_PATH/$DIR_NAME

if [ $? -eq 0 ]
then
        echo
        echo "归档成功"
        echo "归档文件为:$DEST"
else
        echo "归档出现问题"
        echo 
fi
exit

implement

 mkdir /root/archive
 sh tar.sh ../shell/

Timed execution

crontab -e
0 2 * * * /java-project/shell/tar.sh /java-project/shell

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 do not contain regular characters matches itself, for example:

cat /etc/passwd | grep lys

will match all lines containing lys

9.2 Commonly used special characters

  1. Special characters: ^

    ^ matches the beginning of a line, for example:

    cat /etc/passwd | grep ^a
    

    will match all lines starting with a

  2. Special characters: $

    $ matches the end of a line, for example:

    cat /etc/passwd | grep t$
    

    find empty lines

    cat helloworld.sh | grep ^$
    
  3. Special characters:.

    cat /etc/passwd | grep r..t
    

    will match all lines containing rabbit, rbbt, rxdt, root, etc.

  4. Special characters:*

    * Not used alone, it is used in conjunction with the previous character to indicate the previous character 0 or more times, for example

    cat /etc/passwd | grep ro*t
    

    Will match rt, rot, root, roooor, etc.

    .* will match all

  5. Character range (brackets): []

    [] means match a character in a range, for example

    [6,8]-------match 6 or 8,

    [0-9]------Match a 0-9 number

    [0-9]*-----Match a string of numbers of any length

    [az] — match a string between az

    [az]* ------ matches an alphabetic string of any length

    [az,ef]-- matches ac, or any character between ef

    cat /etc/passwd | grep r[a,b,c]*t
    

    Will match rt, rat, raat, etc.

    6 Special characters: \

    ​ \Identifies escape and will not be used alone. Since all special characters have their specific matching patterns, when we want to match a special character itself (for example, I want to find all lines containing '$'), we need to use escaped special characters to represent special the character itself, e.g.

    cat /etc/passwd | grep 'a\$b'
    

    will match all lines containing a$b. Mainly need to use single quotes to enclose the expression,

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 a file and outputs these bytes, characters, and fields.

basic usage

​ cut [option parameter] filename

​ Description: The default delimiter is tab

option parameter Function
-f Column number, which column in advance
-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

data preparation

dong shen
guan zhen
wo wo
lai lai
le le

Cut the first column of cut.txt

cut -d " " -f 1 cut.sh 

intercept the second column

cut -d " " -f 2 cut.sh 

Intercept interval

cut -d " " -f 1-4 cut.sh 
cut -d " " -f -4 cut.sh
cut -d " " -f 4- cut.sh 

cut guan in cut

cat cut.sh | grep guan | cut -d " " -f 1

Select the system PATH variable value, all paths after the second ":" start:

echo $PATH 
/java-project/jdk1.8.0_321/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bi

echo $PATH | cut -d ":" -f 3-
/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

IP address printed after cutting ifconfig

ifconfig ens33 | grep netmask | cut -d " " -f 10

10.2 awk

​ 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.

basic usage

​ awk [option parameter] '/pattern1/{action}' '/patten2/{action2}' filename

​ pattern: Indicates what awk is looking for in the data, which is the matching pattern

​ action: A series of commands executed when matching content

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

Case Practice

(1) Data preparation

Search for all lines starting with the root keyword in the passwd file, and output column 7 of the line

#cut 实现
 cat /etc/passwd | grep ^root | cut -d ";" -f 7
# awk实现
cat /etc/passwd | awk -F ":" '/^root/ {print $7}'
ps -ef | awk '{print $}'
# 打印文件大小
ll -l | awk '{print $5}'

Search for all lines starting with the root keyword in the passwd file, and output the first and seventh columns of the line, separated by "," in the middle.

cat /etc/passwd | awk -F ":" '/^root/ {print $1","$7}'

(4) Only the first and seventh columns of /etc/passwd are displayed, separated by commas, and the column name "begin" is added in front of all lines and "end" is added to the last line

cat /etc/passwd | awk -F ":" 'BEGIN{print "begin"}{print $1","$7}END{print "end"}'

(5) Increase the user id in the passwd file by 1 and output

cat /etc/passwd | awk -F ":" '{print $3+1}'
# 使用变量
cat /etc/passwd | awk -v i=1 -F ":" '{print $3+i}'

Awk's built-in variables

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

Case Practice

​ (1) Count the passwd file name, the line number of each line, and the number of columns of each line

cat /etc/passwd | awk  -F ":" '{print "文件名 :"FILENAME "行号:" NR "列数: "NF }'

(2) Query the line number of the blank line in the ifconfig command and the output result

  ifconfig | awk '/^$/ {print "空行: " NR}' 

11 Comprehensive application

​ We can use the mesg and write tools that come with Linux to send messages to other users.

​ Requirement: To implement a script that quickly sends a message to a certain user, enter the user name as the first parameter, followed by the message to be sent directly. The script needs to detect whether the user is logged in to the system, whether the message function is enabled, and whether the currently sent message is empty.

Pre-knowledge

who 查看有多少控制台
[root@bogon logs]# who
root     pts/0        2022-05-26 17:34 (124.64.252.49)
root     pts/1        2022-05-27 10:12 (120.244.202.117)
root     pts/2        2022-05-27 11:37 (58.34.52.34)
root     pts/5        2022-05-27 10:16 (120.244.202.117)
root     pts/6        2022-05-27 19:10 (120.245.102.201)
root     pts/8        2022-05-25 10:18 (124.64.252.49)

# 向某个控制台发出消息
write root pts/1
hi

​ The script is implemented as follows:

#!/bin/bash/

# 查看用户是否登录
login_user=$(who | grep -i -m 1 $1 | awk '{print $1}' )

if [ -z $login_user ]
then
	echo "$1 不在线!"
	echo "脚本退出"
	exit
fi


# 查看用户是否开启消息功能
is_allowed=$(who -T | grep -i -m 1 $1 | awk '{print $2}' )

if [ $is_allowed != "+" ]
then
	echo "$1 没有开启消息功能"
	echo "脚本退出..."
	exit
fi

# 确认是否有消息发送

if [ -z $2 ]
then
	echo "没有消息发送"
	echo "脚本退出"
	exit
fi


# 从参数中获取要发送的消息
whole_msg=$(echo $* | cut -d " " -f 2-)

# 获取用户登录的终端
user_terminal=$(who | grep -i -m 1 $1 | awk '{print $2}' )


# 写入要发送的消息
echo $whole_msg | write $login_user $user_terminal

if [ $? != 0 ]
then 
	echo "发送失败!"
else
	echo "发送成功!"
fi

exit

get file size

filename="XXXX.jar"
filesize=`ls -l $filename | awk '{ print $5 }'`
filesize=$(stat -c%s "$filename")

Guess you like

Origin blog.csdn.net/weixin_43811294/article/details/126824104