Shell笔记

第1 章Shell 概述

在这里插入图片描述

1)Linux 提供的Shell 解析器有

[yb@hadoop101 ~]$ cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/bin/tcsh
/bin/csh

2)bash 和sh 的关系

[yb@hadoop101 bin]$ ll | grep bash
-rwxr-xr-x. 1 root root 941880 5 月11 2016 bash
lrwxrwxrwx. 1 root root 4 5 月27 2017 sh -> bash

3)Centos 默认的解析器是bash

[yb@hadoop101 bin]$ echo $SHELL
/bin/bash

第2 章Shell 脚本入门

1)脚本格式
脚本以#!/bin/bash 开头(指定解析器)
一般情况下默认的后缀名就是.sh,其实在shell解析的过程当中,对后缀名是没有要求的,只要是可执行文件并且是按照shell的标准去写的都可以解析。

2)第一个Shell 脚本:helloworld.sh
(1)需求:创建一个Shell 脚本,输出helloworld
(2)案例实操:

[yb@hadoop101 shells]$ touch helloworld.sh
[yb@hadoop101 shells]$ vim helloworld.sh

在helloworld.sh 中输入如下内容

#!/bin/bash
echo "helloworld"

(3)脚本的常用执行方式
第一种:采用bash 或sh+脚本的相对路径或绝对路径(不用赋予脚本+x 权限)
sh+脚本的相对路径

[yb@hadoop101 shells]$ sh ./helloworld.sh
Helloworld

sh+脚本的绝对路径

[yb@hadoop101 shells]$ sh /home/yb/shells/helloworld.sh
helloworld

bash+脚本的相对路径

[yb@hadoop101 shells]$ bash ./helloworld.sh
Helloworld

bash+脚本的绝对路径

[yb@hadoop101 shells]$ bash /home/yb/shells/helloworld.sh
Helloworld

第二种:采用输入脚本的绝对路径或相对路径执行脚本(必须具有可执行权限+x)
①首先要赋予helloworld.sh 脚本执行的权限

[yb@hadoop101 shells]$ chmod +x helloworld.sh

②执行脚本
相对路径

[yb@hadoop101 shells]$ ./helloworld.sh
Helloworld

绝对路径

[yb@hadoop101 shells]$ /home/yb/shells/helloworld.sh
Helloworld

注意:第一种执行方法,本质是bash解析器帮你执行脚本,所以脚本本身不需要执行权限。第二种执行方法,本质是脚本需要自己执行,所以需要执行权限。(对于第二种方法,如果你进入到脚本所在目录,然后直接输入脚本的名字helloworld.sh,是不能被执行的,会反馈“bash:helloworld.sh:未找到命令…”,因为此时linux shell默认将它当作一个命令了,但其实没有这个命令所以就这样了。应该输入./helloworld.sh)

第三种:在脚本的路径前加上“.”或者source

[yb@hadoop101 shells]$ source helloworld.sh
helloworld
[yb@hadoop101 shells]$ source /home/yb/shells/helloworld.sh
helloworld
[yb@hadoop101 shells]$. helloworld.sh
helloworld


①有以下脚本

[yb@hadoop101 shells]$ cat test.sh
#!/bin/bash
A=5
echo $A

②分别使用sh,bash,./ 和. 的方式来执行,结果如下:

 
[yb@hadoop101 shells]$ bash test.sh
[yb@hadoop101 shells]$ echo $A

[yb@hadoop101 shells]$ sh test.sh
[yb@hadoop101 shells]$ echo $A

[yb@hadoop101 shells]$ ./test.sh
[yb@hadoop101 shells]$ echo $A

[yb@hadoop101 shells]$ . test.sh
[yb@hadoop101 shells]$ echo $A
5

原因:
前两种方式都是在当前shell 中打开一个子shell 来执行脚本内容,当脚本内容结束,则子shell 关闭,回到父shell 中。第三种,也就是使用在脚本路径前加“.”或者source 的方式,可以使脚本内容在当前shell 里执行,而无需打开子shell!这也是为什么我们每次要修改完/etc/profile 文件以后,需要source 一下的原因。开子shell 与不开子shell 的区别就在于,环境变量的继承关系,如在子shell 中设置的当前变量,父shell 是不可见的。

第3章变量

3.1 系统预定义变量

1)常用系统变量
$HOME、$PWD、$SHELL、$USER 等

2)案例实操
(1)查看系统变量的值

[root@vm100 ~]# echo $HOME
/root

#
[root@vm100 ~]# printenv USER
root

(2)显示当前Shell 中所有变量(包括系统的,用户自定义的,全局的,局部的):set

[yb@hadoop101 shells]$ set
BASH=/bin/bash
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()

(3)查看所有的系统全局变量:env或printenv

[root@vm100 ~]# env
XDG_SESSION_ID=3
HOSTNAME=vm100
SELINUX_ROLE_REQUESTED=
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=192.168.62.1 1872 22
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/1
USER=root
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
MAIL=/var/spool/mail/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
PWD=/root
LANG=en_US.UTF-8
SELINUX_LEVEL_REQUESTED=
HISTCONTROL=ignoredups
SHLVL=1
HOME=/root
LOGNAME=root
XDG_DATA_DIRS=/root/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share
SSH_CONNECTION=192.168.61.1 1872 192.168.61.100 22
LESSOPEN=||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR=/run/user/0
DISPLAY=localhost:11.0
_=/usr/bin/env

#全局变量的校验,打开一个子bash shell 也能看到全局变量。
[root@vm100 ~]# echo $HOME
/root
[root@vm100 ~]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       1828   1789  0 08:52 pts/1    00:00:00 -bash
root       2034   1828  0 09:01 pts/1    00:00:00 ps -f
#打开一个子bash
[root@vm100 ~]# bash
[root@vm100 ~]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       1828   1789  0 08:52 pts/1    00:00:00 -bash
root       2035   1828  0 09:01 pts/1    00:00:00 bash
root       2074   2035  0 09:01 pts/1    00:00:00 ps -f
[root@vm100 ~]# echo $HOME
/root
#退出子bash
[root@vm100 ~]# exit
exit
[root@vm100 ~]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       1828   1789  0 08:52 pts/1    00:00:00 -bash
root       2083   1828  0 09:01 pts/1    00:00:00 ps -f

3.2 自定义变量

1)基本语法
(1)定义变量:变量名=变量值,注意,=号前后不能有空格
(2)撤销变量:unset 变量名
(3)声明静态变量(只读变量;常量):readonly 变量,注意:不能unset
2)变量定义规则
(1)变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建议大写。
(2)等号两侧不能有空格
(3)在bash 中,变量默认类型都是字符串类型,无法直接进行数值运算。
(4)变量的值如果有空格,需要使用双引号或单引号括起来。
3)案例实操
(1)定义变量A

[root@vm100 ~]# A=85
[root@vm100 ~]# echo $A
85
#对于没有申明的变量,echo后是不打印的
[root@vm100 ~]# echo $my_var

[root@vm100 ~]# $my_var=hello
bash: =hello: command not found...
#注意,定义变量时不要加$
[root@vm100 ~]# my_var=hello
[root@vm100 ~]# echo $my_var
hello

(2)给变量A 重新赋值

[yb@hadoop101 shells]$ A=8
[yb@hadoop101 shells]$ echo $A
8
[yb@hadoop101 shells]$ A=1+5
[yb@hadoop101 shells]$ echo $A
1+5
#说明这里的变量类型实际上是默认为字符串的,不能做数值运算。
#如果想要做数值运算可以使用shell里的运算符表达:$(())或$[]
[root@vm100 ~]# A=$((1+5))
[root@vm100 ~]# echo $A
6
[root@vm100 ~]# A=$[8+5]
[root@vm100 ~]# echo $A
13

(3)撤销变量A

[yb@hadoop101 shells]$ unset A
[yb@hadoop101 shells]$ echo $A

(4)声明静态的变量B=2,不能unset

[yb@hadoop101 shells]$ readonly B=2
[yb@hadoop101 shells]$ echo $B
2 [
yb@hadoop101 shells]$ B=9
-bash: B: readonly variable
[root@vm100 ~]# unset B
-bash: unset: B: cannot unset: readonly variable

(5)在bash 中,变量默认类型都是字符串类型,无法直接进行数值运算

[yb@hadoop102 ~]$ C=1+2
[yb@hadoop102 ~]$ echo $C
1+2

(6)变量的值如果有空格,需要使用双引号或单引号括起来

[yb@hadoop102 ~]$ D=I love banzhang
-bash: world: command not found
[yb@hadoop102 ~]$ D="I love banzhang"
[yb@hadoop102 ~]$ echo $D
I love banzhang

(7)可把局部变量提升为全局环境变量,可供其他Shell 程序使用
export 变量名


[root@vm100 ~]# my_var='hello,world'
[root@vm100 ~]# echo $my_var
hello,world
#查看是否是系统定义的全局变量。不是
[root@vm100 ~]# env| grep my_var

#set能看到所有的变量,包括系统的,用户自定义的,全局的,局部的。但是这样还是无法看出my_var是局部变量还是用户自定义的全局变量
[root@vm100 ~]# set |grep my_var
my_var=hello,world

#打开一个子bash
[root@vm100 ~]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       1795   1785  0 08:52 pts/0    00:00:00 -bash
root       2413   1795  0 09:27 pts/0    00:00:00 ps -f
[root@vm100 ~]# bash
[root@vm100 ~]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       1795   1785  0 08:52 pts/0    00:00:00 -bash
root       2414   1795  0 09:27 pts/0    00:00:00 bash
root       2447   2414  0 09:27 pts/0    00:00:00 ps -f
#我们发现在子bash中看不到my_var,说明是一个局部变量
[root@vm100 ~]# echo $my_var

[root@vm100 ~]# exit
exit
[root@vm100 ~]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       1795   1785  0 08:52 pts/0    00:00:00 -bash
root       2456   1795  0 09:29 pts/0    00:00:00 ps -f




#将局部变量变成全局变量。
[root@vm100 ~]# export my_var
[root@vm100 ~]# echo $my_var
hello,world
[root@vm100 ~]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       1795   1785  0 08:52 pts/0    00:00:00 -bash
root       2494   1795  0 09:32 pts/0    00:00:00 ps -f
[root@vm100 ~]# bash
#打开一个子bash,可以看到此时ps -f的PPID是子bash的,说明我们是在子bash中操作
[root@vm100 ~]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       1795   1785  0 08:52 pts/0    00:00:00 -bash
root       2495   1795  0 09:32 pts/0    00:00:00 bash
root       2528   2495  0 09:32 pts/0    00:00:00 ps -f
#子bash中能看到此变量了
[root@vm100 ~]# echo $my_var
hello,world
#在子bash中修改全局变量的值,修改的操作只在子bash中有效。
[root@vm100 ~]# my_var='hello,linux'
[root@vm100 ~]# echo $my_var
hello,linux
#退出子bash,再次查看全局变量的值,发现并未被修改
[root@vm100 ~]# exit
exit
[root@vm100 ~]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       1795   1785  0 08:52 pts/0    00:00:00 -bash
root       2545   1795  0 09:34 pts/0    00:00:00 ps -f
[root@vm100 ~]# echo $my_var
hello,world



#如果在子shell中更改全局变量后再次将它export以后会不会就在父shell中也生效呢?。不会生效
[root@vm100 ~]# bash
[root@vm100 ~]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       1795   1785  0 08:52 pts/0    00:00:00 -bash
root       2623   1795  5 09:42 pts/0    00:00:00 bash
root       2656   2623  0 09:42 pts/0    00:00:00 ps -f
[root@vm100 ~]# my_var="hello,vm"
[root@vm100 ~]# export my_var
[root@vm100 ~]# echo $my_var
hello,vm
[root@vm100 ~]# exit
exit
[root@vm100 ~]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       1795   1785  0 08:52 pts/0    00:00:00 -bash
root       2666   1795  0 09:43 pts/0    00:00:00 ps -f
[root@vm100 ~]# echo $my_var
hello,world

#之前是在命令行中实验,现在在脚本中实验
#my_var是全局变量,
#现在新增加new_var为局部变量
[root@vm100 ~]# new_var='hello,linux'
[root@vm100 ~]# echo $new_var
hello,linux

#打开hello.sh写入如下内容:
	#!/bin/bash
	echo 'hello,world'
	echo $my_var
	echo $new_var

[root@vm100 ~]# vim hello.sh

#运行脚本发现my_var(全局变量)输出了,但是new_var没有输出,因为new_var只是一个局部变量
[root@vm100 ~]# ./hello.sh
hello,world
hello,world

#如果想要局部变量new_var也输出,可以使用source或.的方式执行脚本(因为此方式没有打开子bash)
[root@vm100 ~]# . hello.sh
hello,world
hello,world
hello,linux
[root@vm100 ~]# source hello.sh
hello,world
hello,world
hello,linux


#将局部变量提升为全局变量也可以在子shell中输出new_var
[root@vm100 ~]# export new_var
[root@vm100 ~]# ./hello.sh
hello,world
hello,world
hello,linux



[yb@hadoop101 shells]$ vim helloworld.sh
在helloworld.sh 文件中增加echo $B
#!/bin/bash
echo "helloworld"
echo $B
 
  
   
[yb@hadoop101 shells]$ ./helloworld.sh
Helloworld
发现并没有打印输出变量B 的值。
[yb@hadoop101 shells]$ export B
[yb@hadoop101 shells]$ ./helloworld.sh
helloworld
2

3.3 特殊变量

3.3.1 $n

1)基本语法
$n (功能描述:n 为数字,$0 代表该脚本名称,$1-$9 代表第一到第九个参数,十以上的参数,十以上的参数需要用大括号包含,如${10})
2)案例实操

[root@vm100 ~]# vim hello.sh
#!/bin/bash
echo 'hello,world'
echo 'hello,$1'
[root@vm100 ~]# ./hello.sh
hello,world
hello,$1
#$1应该显示为空的呀,因为我们还没有传参数
[root@vm100 ~]# ./hello.sh xiaoming
hello,world
hello,$1
#$1应该显示xiaoming


#上面的显示有问题,我用vim打开脚本,将单引号换成了双引号以后就正确了。
#双引号引起来就表示变量,单引号不认为引号里面的是变量,会原封不动的输出
[root@vm100 ~]# vim hello.sh
#!/bin/bash
echo 'hello,world'
echo "hello,$1"
[root@vm100 ~]# ./hello.sh
hello,world
hello,
[root@vm100 ~]# ./hello.sh xiaoming
hello,world
hello,xiaoming
[root@vm100 ~]# ./hello.sh xiaoliang
hello,world
hello,xiaoliang

             

[root@vm100 ~]# vim parameter.sh
#!/bin/bash
echo '==============$n============='
#上面使用单引号,因为$n不是一个变量,我们想要原封不动的输出。
echo script name:$0
echo 1st parameter:$1
echo 2st parameter:$2
[root@vm100 ~]# ll
total 20
-rw-------. 1 root root 1906 May 16 21:51 anaconda-ks.cfg
drwxr-xr-x. 2 root root   57 May 25 21:32 Desktop
drwxr-xr-x. 2 root root    6 May 16 21:56 Documents
drwxr-xr-x. 2 root root    6 May 16 21:56 Downloads
-rwxr-xr-x. 1 root root   47 May 30 10:19 hello.sh
drwxr-xr-x. 2 root root    6 May 23 20:10 info
-rw-r--r--. 1 root root 1937 May 16 21:55 initial-setup-ks.cfg
drwxr-xr-x. 2 root root    6 May 16 21:56 Music
-rw-r--r--. 1 root root  205 May 30 10:29 parameter.sh
drwxr-xr-x. 2 root root   53 May 18 10:42 Pictures
drwxr-xr-x. 2 root root    6 May 16 21:56 Public
drwxr-xr-x. 2 root root    6 May 16 21:56 Templates
-rw-r--r--. 1 root root 1242 May 25 21:36 temp.tar.gz
drwxr-xr-x. 2 root root    6 May 16 21:56 Videos
[root@vm100 ~]# chmod +x parameter.sh
[root@vm100 ~]# ll
total 20
-rw-------. 1 root root 1906 May 16 21:51 anaconda-ks.cfg
drwxr-xr-x. 2 root root   57 May 25 21:32 Desktop
drwxr-xr-x. 2 root root    6 May 16 21:56 Documents
drwxr-xr-x. 2 root root    6 May 16 21:56 Downloads
-rwxr-xr-x. 1 root root   47 May 30 10:19 hello.sh
drwxr-xr-x. 2 root root    6 May 23 20:10 info
-rw-r--r--. 1 root root 1937 May 16 21:55 initial-setup-ks.cfg
drwxr-xr-x. 2 root root    6 May 16 21:56 Music
-rwxr-xr-x. 1 root root  205 May 30 10:29 parameter.sh
drwxr-xr-x. 2 root root   53 May 18 10:42 Pictures
drwxr-xr-x. 2 root root    6 May 16 21:56 Public
drwxr-xr-x. 2 root root    6 May 16 21:56 Templates
-rw-r--r--. 1 root root 1242 May 25 21:36 temp.tar.gz
drwxr-xr-x. 2 root root    6 May 16 21:56 Videos
#以相对路径执行,script name显示的是相对路径
[root@vm100 ~]# ./parameter.sh
==============$n=============
script name:./parameter.sh
1st parameter:
2st parameter:
[root@vm100 ~]# ./parameter.sh abc def
==============$n=============
script name:./parameter.sh
1st parameter:abc
2st parameter:def
#以绝对路径执行,script name显示的是绝对路径
[root@vm100 ~]# /root/parameter.sh 123 456
==============$n=============
script name:/root/parameter.sh
1st parameter:123
2st parameter:456
#想要script name:$0只显示脚本的名字,可以使用basename

3.3.2 $#

1)基本语法
$# (功能描述:获取所有输入参数个数,常用于循环,判断参数的个数是否正确以及加强脚本的健壮性)。
2)案例实操

[root@vm100 ~]# vim parameter.sh 

#!/bin/bash
echo '==============$n============='
#上面使用单引号,因为$n不是一个变量,我们想要原封不动
的输出。
echo script name:$0
echo 1st parameter:$1
echo 2st parameter:$2
echo '==============$#============='
echo parameter numbers:$#
[root@vm100 ~]# ./parameter.sh 
==============$n=============
script name:./parameter.sh
1st parameter:
2st parameter:
==============$#=============
parameter numbers:0
[root@vm100 ~]# ./parameter.sh abc def
==============$n=============
script name:./parameter.sh
1st parameter:abc
2st parameter:def
==============$#=============
parameter numbers:2
[root@vm100 ~]# ./parameter.sh abc 
==============$n=============
script name:./parameter.sh
1st parameter:abc
2st parameter:
==============$#=============
parameter numbers:1

3.3.3 $*、$@

1)基本语法
$* (功能描述:这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体)
$@ (功能描述:这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待)(可以用于for循环去遍历参数)
2)案例实操

[root@vm100 ~]# vim parameter.sh 
#!/bin/bash
echo '==============$n============='
#上面使用单引号,因为$n不是一个变量,我们想要原封不动
的输出。
echo script name:$0
echo 1st parameter:$1
echo 2st parameter:$2
echo '==============$#============='
echo parameter numbers:$#
echo '==============$*============='
echo $*
echo '==============$@============='
echo $@
[root@vm100 ~]# ./parameter.sh abc def
==============$n=============
script name:./parameter.sh
1st parameter:abc
2st parameter:def
==============$#=============
parameter numbers:2
==============$*=============
abc def
==============$@=============
abc def

3.3.4 $?

1)基本语法
$? (功能描述:最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了。)
2)案例实操
判断脚本是否正确执行

[root@vm100 ~]# ./parameter.sh abc def
==============$n=============
script name:./parameter.sh
1st parameter:abc
2st parameter:def
==============$#=============
parameter numbers:2
==============$*=============
abc def
==============$@=============
abc def
[root@vm100 ~]# echo $?
0
[root@vm100 ~]# parameter.sh
bash: parameter.sh: command not found...
[root@vm100 ~]# echo $?
127

第4章运算符

1)基本语法
expr 参数1 参数2 参数3 (太麻烦,一般不用)

“$((运算式))” 或“$[运算式]”

(())这个里面可以使用<=,>,>=等符号来表示大小关系
但是[ ]中只能用-lt,-gt等来表示大小关系

2)案例实操:

#这样并未直接计算。
[root@vm100 ~]# a=1+2
[root@vm100 ~]# echo $a
1+2
[root@vm100 ~]# echo 1+2
1+2


[root@vm100 ~]# expr 1+2
1+2
#将1,+,2当成expr的三个参数
[root@vm100 ~]# expr 1 + 2
3
[root@vm100 ~]# expr 8 - 5
3


[root@vm100 ~]# expr 8 * 5
expr: syntax error
#报错:语法错误,因为*在linux里面其实是有很多含义的,如通配符,$*等。要想当作乘法来用,需要加一个转义\
[root@vm100 ~]# expr 8 \* 5
40
#但以上的操作太麻烦了,为了简化,就直接用$((运算式)) 或$[运算式]即可
[root@vm100 ~]# echo $[8*5]
40
[root@vm100 ~]# echo $((8*5))
40
[root@vm100 ~]# S=$[(2+3)*4]
[root@vm100 ~]# echo $S
20



#这样定义变量a是不行的,因为中间有空格就表示一个命令了
[root@vm100 ~]# a=expr 5 \* 2
bash: 5: command not found...
#加个引号试试,也不行,看成字符串了
[root@vm100 ~]# a="expr 5 \* 2"
[root@vm100 ~]# echo $a
expr 5 \* 2
#命令替换:$()或` `,将执行的命令替换成它的值然后赋值给变量a
[root@vm100 ~]# a=$(expr 5 \* 2)
[root@vm100 ~]# echo $a
10
[root@vm100 ~]# a=`expr 5 \* 2`
[root@vm100 ~]# echo $a
10

[root@vm100 ~]# vim add.sh
#!/bin/bash
sum=$[$1+$2]
echo sum=$sum
#上面这行的sum是字符串,要输出显示“sum”,$sum才是第一行计算的结果
[root@vm100 ~]# ll
total 24
-rw-r--r--. 1 root root  138 May 30 14:15 add.sh
-rw-------. 1 root root 1906 May 16 21:51 anaconda-ks.cfg
drwxr-xr-x. 2 root root   57 May 25 21:32 Desktop
drwxr-xr-x. 2 root root    6 May 16 21:56 Documents
drwxr-xr-x. 2 root root    6 May 16 21:56 Downloads
-rwxr-xr-x. 1 root root   47 May 30 10:19 hello.sh
drwxr-xr-x. 2 root root    6 May 23 20:10 info
-rw-r--r--. 1 root root 1937 May 16 21:55 initial-setup-ks.cfg
drwxr-xr-x. 2 root root    6 May 16 21:56 Music
-rwxr-xr-x. 1 root root  359 May 30 10:45 parameter.sh
drwxr-xr-x. 2 root root   53 May 18 10:42 Pictures
drwxr-xr-x. 2 root root    6 May 16 21:56 Public
drwxr-xr-x. 2 root root    6 May 16 21:56 Templates
-rw-r--r--. 1 root root 1242 May 25 21:36 temp.tar.gz
drwxr-xr-x. 2 root root    6 May 16 21:56 Videos
[root@vm100 ~]# chmod +x add.sh
[root@vm100 ~]# ll
total 24
-rwxr-xr-x. 1 root root  138 May 30 14:15 add.sh
-rw-------. 1 root root 1906 May 16 21:51 anaconda-ks.cfg
drwxr-xr-x. 2 root root   57 May 25 21:32 Desktop
drwxr-xr-x. 2 root root    6 May 16 21:56 Documents
drwxr-xr-x. 2 root root    6 May 16 21:56 Downloads
-rwxr-xr-x. 1 root root   47 May 30 10:19 hello.sh
drwxr-xr-x. 2 root root    6 May 23 20:10 info
-rw-r--r--. 1 root root 1937 May 16 21:55 initial-setup-ks.cfg
drwxr-xr-x. 2 root root    6 May 16 21:56 Music
-rwxr-xr-x. 1 root root  359 May 30 10:45 parameter.sh
drwxr-xr-x. 2 root root   53 May 18 10:42 Pictures
drwxr-xr-x. 2 root root    6 May 16 21:56 Public
drwxr-xr-x. 2 root root    6 May 16 21:56 Templates
-rw-r--r--. 1 root root 1242 May 25 21:36 temp.tar.gz
drwxr-xr-x. 2 root root    6 May 16 21:56 Videos
[root@vm100 ~]# ./add.sh 8 5
sum=13

第5章条件判断

1)基本语法
(1)test condition(注意如果condition里有=或!=,必须=或!=前后都要有空格才可以!!!)
(2)[空格condition空格](注意condition 前后要有空格,如果condition里有=,必须=前后都要有空格才可以!!!)
注意:条件非空即为true,如:[ yb ]返回true,[ ] 返回false。

2)常用判断条件
(1)两个整数之间比较
-eq 等于(equal) -ne 不等于(not equal)
-lt 小于(less than) -le 小于等于(less equal)
-gt 大于(greater than) -ge 大于等于(greater equal)
-a 逻辑与(and) -o 逻辑或(or)
注:如果是字符串之间的比较,用等号“=”判断相等;用“!=”判断不等。
(())这个里面可以使用<=,>,>=等符号来表示大小关系
但是[ ]中只能用-lt,-gt等来表示大小关系
(2)按照文件权限进行判断
-r 有读的权限(read)
-w 有写的权限(write)
-x 有执行的权限(execute)
(3)按照文件类型进行判断
-e 文件存在(existence)
-f 文件存在并且是一个常规的文件(file)
-d 文件存在并且是一个目录(directory)

3)逻辑与&&,逻辑或||
多条件判断(&& 表示前一条命令执行成功时,才执行后一条命令,|| 表示上一条命令执行失败后,才执行下一条命令)相当于java的三元运算符。
-a 逻辑与(and) -o 逻辑或(or)

4)案例实操

(0)a是否为hello

[root@vm100 scripts]# a=hello
[root@vm100 scripts]# test $a=hello
[root@vm100 scripts]# echo $?
0
#0说明之前的测试通过了,但后面两次测试时全都显示的是0,显然是有问题的。注意condition前后都要有空格!!!
[root@vm100 scripts]# test $a=HELLO
[root@vm100 scripts]# echo $?
0
[root@vm100 scripts]# test $a=abc
[root@vm100 scripts]# echo $?
0



#这也是不行的
[root@vm100 scripts]# echo $a
hello
[root@vm100 scripts]# test $a= def
-bash: test: hello=: unary operator expected
[root@vm100 scripts]# test $a= 123
-bash: test: hello=: unary operator expected
[root@vm100 scripts]# test $a = 123
[root@vm100 scripts]# test $a =abc
-bash: test: hello: unary operator expected



#=前后都要有空格才是对的!!!!返回0表示正确,返回1表示错误
[root@vm100 scripts]# echo $a
hello
[root@vm100 scripts]# test $a = abc
[root@vm100 scripts]# echo $?
1
[root@vm100 scripts]# test $a = HELLO
[root@vm100 scripts]# echo $?
1
[root@vm100 scripts]# test $a = hello
[root@vm100 scripts]# echo $?
0
[root@vm100 scripts]# [ $a != hello ]
[root@vm100 scripts]# echo $?
1
[root@vm100 scripts]# [ $a != abc ]
[root@vm100 scripts]# echo $?
0





#使用[空格condition空格](注意condition 前后要有空格,如果condition里有=,必须=前后都要有空格才可以!!!)
[root@vm100 scripts]# echo $a
hello
[root@vm100 scripts]# [ $a=abc ]
[root@vm100 scripts]# echo $?
0#有问题
#从上方可知condition里有=,必须=前后都要有空格才可以!!!
[root@vm100 scripts]# echo $a
hello
[root@vm100 scripts]# [ $a = abc ]
[root@vm100 scripts]# echo $?
1
[root@vm100 scripts]# [ $a = hello ]
[root@vm100 scripts]# echo $?
0

#有值为真-0,无值为假-1
[root@vm100 scripts]# [ asd ]
[root@vm100 scripts]# echo $?
0
[root@vm100 scripts]# [ ]
[root@vm100 scripts]# echo $?
1




#对于数的比较,如果把它看作数字(整数)则需要用-eq,-ne,-lt等,这里用=比较2和8是将2和8都看作字符串去比较的。
[root@vm100 scripts]# [ 2 = 8 ]
[root@vm100 scripts]# echo $?
1
[root@vm100 scripts]# [ 2 = 2 ]
[root@vm100 scripts]# echo $?
0
[root@vm100 scripts]# [ 2.1 = 2.1 ]
[root@vm100 scripts]# echo $?
0

(1)23 是否大于等于22

[yb@hadoop101 shells]$ [ 23 -ge 22 ]
[yb@hadoop101 shells]$ echo $?
0

(2)helloworld.sh 是否具有写权限

[yb@hadoop101 shells]$ [ -w helloworld.sh ]
[yb@hadoop101 shells]$ echo $?
0

(3)/home/yb/cls.txt 目录中的文件是否存在

[yb@hadoop101 shells]$ [ -e /home/yb/cls.txt ]
[yb@hadoop101 shells]$ echo $?
1

(4)多条件判断(&& 表示前一条命令执行成功时,才执行后一条命令,|| 表示上一条命令执行失败后,才执行下一条命令)相当于java的三元运算符

[yb@hadoop101 ~]$ [ yb ] && echo OK || echo notOK
OK
[yb@hadoop101 shells]$ [ ] && echo OK || echo notOK
notOK

第6 章流程控制(重点)

6.1 if 判断

1)基本语法
(1)单分支

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

或者

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

if [ 条件判断式 ];then 程序;fi
#;的意思就是在同一行中,写多条命令,用;进行区分

或将上面3种中的[ 条件判断式 ]都换成(())也可以
(())这个里面可以使用<=,>,>=等符号来表示大小关系
但是[ ]中只能用-lt,-gt等来表示大小关系
(2)多分支

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

注意事项:
①[ 条件判断式 ],中括号和条件判断式之间必须有空格
②if 后要有空格

2)案例实操

[root@vm100 ~]# a=85
[root@vm100 ~]# if [ $a  -gt 60 ];then echo ok;fi 
ok
[root@vm100 scripts]# a=22
[root@vm100 scripts]# if [ $a -gt 18 ] && [ $a -lt 35 ];then echo ok ; fi
ok
#上面是用&&将两个[]连在一起,那么时候可以在同一个[]中用&&连接两个表达式呢?可以的。但不能像下面这行这样写:
[root@vm100 scripts]# if [ $a -gt 18  && $a -lt 35 ];then echo ok ; fi
-bash: [: missing `]'
#应该要用-a(and)这样:
[root@vm100 scripts]# if [ $a -gt 18  -a  $a -lt 35 ];then echo ok ; fi
ok




[root@vm100 scripts]# a=3
[root@vm100 scripts]# if (($a>5));then echo ok;else echo notok; fi
notok



[root@vm100 scripts]# vim if_test.sh
#!/bin/bash
if [ $1 = yb  ]
then
        echo hello yb
fi
[root@vm100 scripts]# ll
total 16
-rwxr-xr-x. 1 root root 135 May 30 14:21 add.sh
-rwxr-xr-x. 1 root root  47 May 30 10:19 hello.sh
-rw-r--r--. 1 root root  51 May 30 16:04 if_test.sh
-rwxr-xr-x. 1 root root 359 May 30 10:45 parameter.sh
[root@vm100 scripts]# chmod +x if_test.sh 
[root@vm100 scripts]# ll
total 16
-rwxr-xr-x. 1 root root 135 May 30 14:21 add.sh
-rwxr-xr-x. 1 root root  47 May 30 10:19 hello.sh
-rwxr-xr-x. 1 root root  51 May 30 16:04 if_test.sh
-rwxr-xr-x. 1 root root 359 May 30 10:45 parameter.sh     
[root@vm100 scripts]# ./if_test.sh 
./if_test.sh: line 2: [: =: unary operator expecte
#报错期待一元表达式。因为if [ $1 = yb  ]这里$1我们没有传参,是空,就有问题,
#所以我们一般要将$1写成"$1"x,yb写成"yb"x。这个x相当于是一个拼接上去的x,这样至少保证了这个字符串不为空
[root@vm100 scripts]# vim if_test.sh
#!/bin/bash
if [ "$1"x = "yb"x  ]
then
        echo hello yb
fi
[root@vm100 scripts]# ./if_test.sh 
[root@vm100 scripts]# ./if_test.sh yb
hello yb
[root@vm100 scripts]# ./if_test.sh ab
                                               



[root@vm100 scripts]# vim if_test.sh 
#!/bin/bash
if [ "$1"x = "yb"x  ]
then
        echo hello yb
fi
#输入第二个参数,表示年龄,判断属于哪个年龄段
if [ $2 -lt 18  ]
then
        echo "未成年人"
else
        echo "成年人"
fi
[root@vm100 scripts]# ./if_test.sh yb 22
hello yb
成年人
[root@vm100 scripts]# ./if_test.sh yb 15
hello yb
未成年人



#多分支
[root@vm100 scripts]# vim if_test.sh 
#!/bin/bash
if [ "$1"x = "yb"x  ]
then
        echo hello yb
fi

#输入第二个参数,表示年龄,判断属于哪个年龄段
if [ $2 -lt 18  ]
then
        echo "未成年人"
elif [ $2 -lt 35 ]
then
        echo "青年人"
elif [ $2 -lt 60 ]
then
        echo "中年人"
else
        echo "老年人"
fi
[root@vm100 scripts]# ./if_test.sh yb 15
hello yb
未成年人
[root@vm100 scripts]# ./if_test.sh yb 22
hello yb
青年人
[root@vm100 scripts]# ./if_test.sh yb 36
hello yb
中年人
[root@vm100 scripts]# ./if_test.sh yb 90
hello yb
老年人


输入一个数字,如果是1,则输出banzhang zhen shuai,如果是2,则输出cls zhen mei,如果是其它,什么也不输出。

[yb@hadoop101 shells]$ touch if.sh
[yb@hadoop101 shells]$ vim if.sh
 
  
   
#!/bin/bash
if [ $1 -eq 1 ]
then
echo "banzhang zhen shuai"
elif [ $1 -eq 2 ]
then
echo "cls zhen mei"
fi
[yb@hadoop101 shells]$ chmod 777 if.sh
[yb@hadoop101 shells]$ ./if.sh 1
banzhang zhen shuai

6.2 case 语句

1)基本语法

case $变量名in
值1)
如果变量的值等于值1,则执行程序1
;;
值2)
如果变量的值等于值2,则执行程序2
;;
…省略其他分支…
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac

注意事项:
(1)case 行尾必须为单词“in”,每一个模式匹配必须以右括号“)”结束。
(2)双分号“;;”表示命令序列结束,相当于java 中的break。
(3)最后的“*)”表示默认模式,相当于java 中的default。

2)案例实操

[root@vm100 scripts]# vim case_test.sh
#!/bin/bash

case $1 in
1)
        echo "one"
;;
2)
        echo "two"
;;
3)
        echo "three"
;;
*)
        echo "number else"
;;
esac
[root@vm100 scripts]# chmod +x case_test.sh 
[root@vm100 scripts]# ll
total 20
-rwxr-xr-x. 1 root root 135 May 30 14:21 add.sh
-rwxr-xr-x. 1 root root 111 Apr  1 10:36 case_test.sh
-rwxr-xr-x. 1 root root  47 May 30 10:19 hello.sh
-rwxr-xr-x. 1 root root 282 May 30 17:26 if_test.sh
-rwxr-xr-x. 1 root root 359 May 30 10:45 parameter.sh
[root@vm100 scripts]# ./case_test.sh  2
two
[root@vm100 scripts]# ./case_test.sh  1
one
[root@vm100 scripts]# ./case_test.sh  6
number else

输入一个数字,如果是1,则输出banzhang,如果是2,则输出cls,如果是其它,输出renyao。

[yb@hadoop101 shells]$ touch case.sh
[yb@hadoop101 shells]$ vim case.sh
!/bin/bash
case $1 in
"1")
echo "banzhang"
;;
"2")
echo "cls"
;;
*)  
echo "renyao"
;;
esac
[yb@hadoop101 shells]$ chmod 777 case.sh
[yb@hadoop101 shells]$ ./case.sh 1
1

6.3 for 循环

1)基本语法1

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

2)案例实操
从1 加到100

[root@vm100 scripts]# vim sum_to.sh 
#!/bin/bash
# 用for进行实现
for (( i=1; i <= $1; i++  ))
#注意这里小于等于没有用-le,而是用的<=,因为是双(),所以可以这样写
do
        sum=$[ $sum + $i ]
        #注意这里的写法,使用变量时要加$
done
echo $sum

# 用while做一个实现
a=1
while [ $a -le $1 ]
do
#       sum2=$[ $sum2 + $a ]
#       a=$[$a + 1]
        let sum2+=a
        let a++
done
echo $sum2
[root@vm100 scripts]# ll
total 24
-rwxr-xr-x. 1 root root 135 May 30 14:21 add.sh
-rwxr-xr-x. 1 root root 111 Apr  1 10:36 case_test.sh
-rwxr-xr-x. 1 root root  47 May 30 10:19 hello.sh
-rwxr-xr-x. 1 root root 282 May 30 17:26 if_test.sh
-rwxr-xr-x. 1 root root 359 May 30 10:45 parameter.sh
-rw-r--r--. 1 root root 230 Apr  1 10:36 sum_to.sh
[root@vm100 scripts]# chmod +x sum_to.sh 
[root@vm100 scripts]# ll
total 24
-rwxr-xr-x. 1 root root 135 May 30 14:21 add.sh
-rwxr-xr-x. 1 root root 111 Apr  1 10:36 case_test.sh
-rwxr-xr-x. 1 root root  47 May 30 10:19 hello.sh
-rwxr-xr-x. 1 root root 282 May 30 17:26 if_test.sh
-rwxr-xr-x. 1 root root 359 May 30 10:45 parameter.sh
-rwxr-xr-x. 1 root root 230 Apr  1 10:36 sum_to.sh
[root@vm100 scripts]# ./sum_to.sh 100
5050
5050


[yb@hadoop101 shells]$ touch for1.sh
[yb@hadoop101 shells]$ vim for1.sh
#!/bin/bash
sum=0
for((i=0;i<=100;i++))
do
	sum=$[$sum+$i]
done
echo $sum
[yb@hadoop101 shells]$ chmod 777 for1.sh
[yb@hadoop101 shells]$ ./for1.sh
5050

3)基本语法2(常用)

for 变量in 值1 值2 值3…
do
	程序
done

4)案例实操

[root@vm100 scripts]# for os in linux windows macos; do echo $os; done
linux
windows
macos



[root@vm100 ~]# for i in { 1..100 }; do sum=$[$sum+$i]; done
-bash: +{: syntax error: operand expected (error token is "{")
#{ 1..100 }这样不行,要把空格去掉
[root@vm100 ~]# for i in {1..100}; do sum=$[$sum+$i]; done
[root@vm100 ~]# echo $sum
5050
#{1..100}是从1到100的意思,包括1和100,类似于java的增强for循环


(1)打印所有输入参数

[yb@hadoop101 shells]$ touch for2.sh
[yb@hadoop101 shells]$ vim for2.sh
#!/bin/bash
#打印数字
for i in cls mly wls
do
	echo "ban zhang love $i"
done
[yb@hadoop101 shells]$ chmod 777 for2.sh
[yb@hadoop101 shells]$ ./for2.sh
ban zhang love cls
ban zhang love mly
ban zhang love wls

(2)比较 ∗ 和 *和 @区别
$*和$@都表示传递给函数或脚本的所有参数,不被双引号“”包含时,都以$1 $2 …$n的形式输出所有参数。

[yb@hadoop101 shells]$ touch for3.sh
[yb@hadoop101 shells]$ vim for3.sh
#!/bin/bash
echo '=============$*============='
for i in $*
do
echo "ban zhang love $i"
done
echo '=============$@============='
for j in $@
do
echo "ban zhang love $j"
done
[yb@hadoop101 shells]$ chmod 777 for3.sh
[yb@hadoop101 shells]$ ./for3.sh cls mly wls
=============$*=============
banzhang love cls
banzhang love mly
banzhang love wls
=============$@=============
banzhang love cls
banzhang love mly
banzhang love wls

当它们被双引号“”包含时,$*会将所有的参数作为一个整体,以“$1 $2 …$n”的形式输出所有参数;$@会将各个参数分开,以“$1” “$2”…“$n”的形式输出所有参数。

[yb@hadoop101 shells]$ vim for4.sh
#!/bin/bash
echo '=============$*============='
for i in "$*"
#$*中的所有参数看成是一个整体,所以这个for 循环只会循环一次
do
echo "ban zhang love $i"
done
echo '=============$@============='
for j in "$@"
#$@中的每个参数都看成是独立的,所以“$@”中有几个参数,就会循环几次
do
echo "ban zhang love $j"
done
[yb@hadoop101 shells]$ chmod 777 for4.sh
[yb@hadoop101 shells]$ ./for4.sh cls mly wls
=============$*=============
banzhang love cls mly wls
=============$@=============
banzhang love cls
banzhang love mly 
banzhang love wls
#当@*和$@不被双引号引起来的时候,输出没有区别
[root@vm100 scripts]# vim parameter_for_test.sh 
#!/bin/bash
echo '=============$*================='
for para in $*
do
        echo $para
done

echo '=============$@================='
for para in $@
do
        echo $para
done
[root@vm100 scripts]# chmod +x parameter_for_test.sh 
[root@vm100 scripts]# ll
total 28
-rwxr-xr-x. 1 root root 135 May 30 14:21 add.sh
-rwxr-xr-x. 1 root root 111 Apr  1 10:36 case_test.sh
-rwxr-xr-x. 1 root root  47 May 30 10:19 hello.sh
-rwxr-xr-x. 1 root root 282 May 30 17:26 if_test.sh
-rwxr-xr-x. 1 root root 168 Apr  1 10:36 parameter_for_test.sh
-rwxr-xr-x. 1 root root 359 May 30 10:45 parameter.sh
-rwxr-xr-x. 1 root root 230 Apr  1 10:36 sum_to.sh
[root@vm100 scripts]# ./parameter_for_test.sh a b c d e f g 
=============$*=================
a
b
c
d
e
f
g
=============$@=================
a
b
c
d
e
f
g


#当@*和$@被双引号引起来的时候,输出有区别
[root@vm100 scripts]# vim parameter_for_test.sh 
#!/bin/bash

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

echo '=============$@================='
for para in "$@"
do
        echo $para
done
#"$*"把所有参数都当成一个整体输出,"$@"把每个参数作为独立的数据来处理
[root@vm100 scripts]# ./parameter_for_test.sh a b c d e f g 
=============$*=================
a b c d e f g
=============$@=================
a
b
c
d
e
f
g



6.4 while 循环

1)基本语法

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

2)案例实操
从1 加到100

[root@vm100 scripts]# vim sum_to.sh 
#!/bin/bash
# 用while做一个实现
a=1
while [ $a -le $1 ]
do
#       sum2=$[ $sum2 + $a ]
#       a=$[$a + 1]
#上面两行的效果和下面两行一样
        let sum2+=a #这里+=前后不能有空格
        let a++
done
echo $sum2
[root@vm100 scripts]# ll
total 24
-rwxr-xr-x. 1 root root 135 May 30 14:21 add.sh
-rwxr-xr-x. 1 root root 111 Apr  1 10:36 case_test.sh
-rwxr-xr-x. 1 root root  47 May 30 10:19 hello.sh
-rwxr-xr-x. 1 root root 282 May 30 17:26 if_test.sh
-rwxr-xr-x. 1 root root 359 May 30 10:45 parameter.sh
-rw-r--r--. 1 root root 230 Apr  1 10:36 sum_to.sh
[root@vm100 scripts]# chmod +x sum_to.sh 
[root@vm100 scripts]# ll
total 24
-rwxr-xr-x. 1 root root 135 May 30 14:21 add.sh
-rwxr-xr-x. 1 root root 111 Apr  1 10:36 case_test.sh
-rwxr-xr-x. 1 root root  47 May 30 10:19 hello.sh
-rwxr-xr-x. 1 root root 282 May 30 17:26 if_test.sh
-rwxr-xr-x. 1 root root 359 May 30 10:45 parameter.sh
-rwxr-xr-x. 1 root root 230 Apr  1 10:36 sum_to.sh
[root@vm100 scripts]# ./sum_to.sh 100
5050

[yb@hadoop101 shells]$ touch while.sh
[yb@hadoop101 shells]$ vim while.sh
#!/bin/bash
sum=0
i=1
while [ $i -le 100 ]
do
sum=$[$sum+$i]
i=$[$i+1]
done
echo $sum
[yb@hadoop101 shells]$ chmod 777 while.sh
[yb@hadoop101 shells]$ ./while.sh
5050

第7 章read 读取控制台输入

1)基本语法
read (选项) (参数)
①选项:
-p 提示信息:指定读取值时的提示信息;
-t 数字:指定读取值时等待的时间(秒)如果不加-t 表示一直等待直到用户输入
②参数
变量:指定读取值的变量名
2)案例实操

[root@vm100 ~]# vim read_test.sh 
#!/bin/bash

read -t 10 -p "请输入您的名字:" name
echo "welcome, $name"
[root@vm100 ~]# chmod +x read_test.sh 
[root@vm100 ~]# ./read_test.sh 
请输入您的名字:wtt
welcome, wtt
#如果不输入,一直等待10秒后就会自动输出了
[root@vm100 ~]# ./read_test.sh 
请输入您的名字:welcome, 

提示7 秒内,读取控制台输入的名称

[yb@hadoop101 shells]$ touch read.sh
[yb@hadoop101 shells]$ vim read.sh
#!/bin/bash
read -t 7 -p "Enter your name in 7 seconds :" NN
echo $NN
[yb@hadoop101 shells]$ ./read.sh
Enter your name in 7 seconds : yb
yb

第8 章函数

函数就是具有某功能的代码块,函数与脚本的区别在于:脚本没有返回值,它的返回非常简陋,只能用$?来判断是否操作成功;脚本的调用比较笨拙。函数就是灵活版的脚本,脚本就是笨重版的函数。

8.1 系统函数

(可以认为命令替换就是系统函数的调用)

8.1.1 basename

1)基本语法
basename [string / pathname] [suffix] (功能描述:basename 命令会删掉所有的前缀包括最后一个(‘/’)字符,然后将字符串显示出来。
basename 可以理解为取路径里的文件名称。取的是给定字符串的最后一个\后面的内容。
选项:
suffix 为后缀,如果suffix 被指定了,basename 会将pathname 或string 中的suffix 去掉。

在脚本中使用函数时需要用到命令替换:$()或 ,将函数替换成它得到的值再参与操作:

[root@vm100 ~]# vim cmd_test.sh 
#!/bin/bash

filename="$1"_log_$(date +%s)
echo $filename
#date +%s 就是函数date的一种用法,获得时间戳,我们在脚本中使用时应该用“命令替换”
[root@vm100 scripts]# chmod +x cmd_test.sh 
[root@vm100 scripts]# ./cmd_test.sh  hello1
hello1_log_1653916861



2)案例实操

[root@vm100 scripts]# basename abc/dfe/aaa.txt
aaa.txt
[root@vm100 scripts]# basename ./aa/abc
abc
#basename的本质不是去找这个“路径”,只是截取最后的名字而已,相当于做一个字符串的剪切。



#之前的parameter.sh中使用$0得到的时包含路径的东西:
[root@vm100 scripts]# vim parameter.sh
#!/bin/bash
echo '==============$n============='
#上面使用单引号,因为$n不是一个变量,我们想要原封不动的输出。
echo script name:$0
echo 1st parameter:$1
echo 2st parameter:$2
echo '==============$#============='
echo parameter numbers:$#
echo '==============$*============='
echo $*
echo '==============$@============='
echo $@
[root@vm100 scripts]# ./parameter.sh hello world
==============$n=============
script name:./parameter.sh
1st parameter:hello
2st parameter:world
==============$#=============
parameter numbers:2
==============$*=============
hello world
==============$@=============
hello world
#现在我们希望$0只得到文件名,不要路径,就是用basename函数(要用到命令替换)
[root@vm100 scripts]# vim parameter.sh 
#!/bin/bash
echo '==============$n============='
#上面使用单引号,因为$n不是一个变量,我们想要原封不动的输出。
echo script name:$(basename $0)
echo 1st parameter:$1
echo 2st parameter:$2
echo '==============$#============='
echo parameter numbers:$#
echo '==============$*============='
echo $*
echo '==============$@============='
echo $@
[root@vm100 scripts]# ./parameter.sh hello world
==============$n=============
script name:parameter.sh
1st parameter:hello
2st parameter:world
==============$#=============
parameter numbers:2
==============$*=============
hello world
==============$@=============
hello world

#把后缀和路径都去掉
[root@vm100 scripts]# vim parameter.sh 
#!/bin/bash
echo '==============$n============='
#上面使用单引号,因为$n不是一个变量,我们想要原封不动的输出。
echo script name:$(basename $0 .sh)
echo 1st parameter:$1
echo 2st parameter:$2
echo '==============$#============='
echo parameter numbers:$#
echo '==============$*============='
echo $*
echo '==============$@============='
echo $@
[root@vm100 scripts]# ./parameter.sh hello world
==============$n=============
script name:parameter
1st parameter:hello
2st parameter:world
==============$#=============
parameter numbers:2
==============$*=============
hello world
==============$@=============
hello world

截取该/home/yb/banzhang.txt 路径的文件名称。

[yb@hadoop101 shells]$ basename /home/yb/banzhang.txt
banzhang.txt
[yb@hadoop101 shells]$ basename /home/yb/banzhang.txt .txt
banzhang

8.1.2 dirname

1)基本语法
dirname 文件(绝对)路径(功能描述:从给定的包含(绝对)路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录的部分))
dirname 可以理解为取文件路径的(绝对)路径名称,取的是给定字符串的最后一个\前面的内容。
2)案例实操

[root@vm100 scripts]# dirname /root/scripts/parameter.sh 
/root/scripts
[root@vm100 scripts]# dirname ./abc/dfe/ghi
./abc/dfe



#修改parameter.sh获取它的路径
[root@vm100 scripts]# vim parameter.sh 

#!/bin/bash
echo '==============$n============='
#上面使用单引号,因为$n不是一个变量,我们想要原封不动的输出。
echo script name:$(basename $0 .sh)
cd $(dirname $0)
echo script path:$(pwd)
#上面这两步也可以合成一步,用;隔开即可:echo script path:$(cd $(dirname $0);pwd)

echo 1st parameter:$1
echo 2st parameter:$2
echo '==============$#============='
echo parameter numbers:$#
echo '==============$*============='
echo $*
echo '==============$@============='
echo $@
[root@vm100 scripts]# ./parameter.sh hello world
==============$n=============
script name:parameter
script path:/root/scripts
1st parameter:hello
2st parameter:world
==============$#=============
parameter numbers:2
==============$*=============
hello world
==============$@=============
hello world

获取banzhang.txt 文件的路径。

[yb@hadoop101 ~]$ dirname /home/yb/banzhang.txt
/home/yb

8.2 自定义函数

1)基本语法

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

2)经验技巧
(1)必须在调用函数地方之前,先声明函数,shell 脚本是逐行运行。不会像其它语言一
样先编译。
(2)函数返回值,只能通过$?系统变量获得,可以加:return 返回某int值,return什么就返回什么,也可以不加return,如果不加,将以函数体里面最后一条命令运行结果作为返回值。$?实际上不是想返回什么就返回什么的,它返回的其实是执行结果成功与否的一个码,如果是0则表示执行成功,一般返回的就是0-255,所以return 后跟整数数值n(0-255)。如果想返回其他结果也是可以的,具体看案例

3)案例实操

[root@vm100 scripts]# vim fun_test.sh 
#!/bin/bash

function add(){
        s=$[$1 + $2] #$[运算式]
        echo "和:" $s
}

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

add $a $b
[root@vm100 scripts]# chmod +x fun_test.sh 
[root@vm100 scripts]# ll
total 36
-rwxr-xr-x. 1 root root 135 May 30 14:21 add.sh
-rwxr-xr-x. 1 root root 111 Apr  1 10:36 case_test.sh
-rwxr-xr-x. 1 root root  58 Apr  1 10:36 cmd_test.sh
-rwxr-xr-x. 1 root root 245 Jun  1 15:32 fun_test.sh
-rwxr-xr-x. 1 root root  47 May 30 10:19 hello.sh
-rwxr-xr-x. 1 root root 282 May 30 17:26 if_test.sh
-rwxr-xr-x. 1 root root 168 May 30 20:11 parameter_for_test.sh
-rwxr-xr-x. 1 root root 516 Jun  1 11:29 parameter.sh
-rwxr-xr-x. 1 root root 230 Apr  1 10:36 sum_to.sh
[root@vm100 scripts]# ./fun_test.sh 
请输入第一个整数:8
请输入第二个整数:5
和: 13


#上面的fun_test.sh没有返回值,只是echo打印了一下而已,如果我们想真的捕获到函数的返回值,在函数外用echo打印返回值,而不是在函数中用ehco打印某个东西的话就这样:
[root@vm100 scripts]# vim fun_test.sh 
#!/bin/bash
function add(){
        s=$[$1 + $2] #$[运算式]
        #echo "和:" $s
        #上面的echo改成return
        return "和:"$s
}

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


add $a $b
echo $?#显示上一步的返回值
[root@vm100 scripts]# ./fun_test.sh 
请输入第一个整数:8
请输入第二个整数:5
./fun_test.sh: line 7: return: 和:13: numeric argument required
255
#报错:需要数字参数。
#为何这样报错,因为return的东西是要给到$?的,$?表示的是一个执行结果的代码,这个码只能是0-255,所以不能有字符串
#那我们就把reurn处的“和:”去掉,放到函数外的echo处
[root@vm100 scripts]# vim fun_test.sh 
#!/bin/bash
function add(){
        s=$[$1 + $2] #$[运算式]
        #echo "和:" $s
        #上面的echo改成return
        return $s
}

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


add $a $b
echo "和:"$?
[root@vm100 scripts]# ./fun_test.sh 
请输入第一个整数:8
请输入第二个整数:5
和:13
[root@vm100 scripts]# ./fun_test.sh 85
请输入第一个整数:9785
请输入第二个整数:85
和:142
#这样就捕捉到了add的执行结果
#但又有一个问题:之前说了return的值只能是0-255,如果两个数字比较大,和超过了255虽然不报错,但和的结果是错误的。如果是函数里接return返回的话,那就只能捕获一个0-255的值,然后传递给$?。
#干脆就不要return,用echo $s但是echo只是打印,并不是返回值,怎么返回呢?会回忆统函数的调用方式,额可以在调用之后做一个命令替换,就可以把返回的值赋给另一个变量了
[root@vm100 scripts]# vim fun_test.sh 
function add(){
        s=$[$1 + $2] #$[运算式]
        #echo "和:" $s
        #上面的echo改成return
        echo $s
}

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


#add $a $b
#echo "和:"$?

sum=$(add $a $b) #命令替换。add $a $b 得到的结果就是echo的$s
echo "和:" $sum
echo "和的平方:" $[ $sum * $sum ]

[root@vm100 scripts]# ./fun_test.sh 
请输入第一个整数:8
请输入第二个整数:5
和: 13
和的平方: 169

计算两个输入参数的和。

[yb@hadoop101 shells]$ touch fun.sh
[yb@hadoop101 shells]$ vim fun.sh
#!/bin/bash
function sum()
{
s=0
s=$[$1+$2]
echo "$s"
}
read -p "Please input the number1: " n1;
read -p "Please input the number2: " n2;
sum $n1 $n2;
[yb@hadoop101 shells]$ chmod 777 fun.sh
[yb@hadoop101 shells]$ ./fun.sh
Please input the number1: 2
Please input the number2: 5
7

第9 章正则表达式入门

正则表达式使用单个字符串来描述、匹配一系列符合某个语法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。在Linux 中,grep,sed,awk 等文本处理工具都支持通过正则表达式进行模式匹配。

9.1 常规匹配

一串不包含特殊字符的正则表达式匹配它自己,例如:

[yb@hadoop101 shells]$ cat /etc/passwd | grep yb

就会匹配所有包含yb 的行。

9.2 常用特殊字符

1)特殊字符:^
^ 匹配一行的开头,例如:

[yb@hadoop101 shells]$ cat /etc/passwd | grep ^a

会匹配出所有以a 开头的行
2)特殊字符:$
$ 匹配一行的结束,例如

[yb@hadoop101 shells]$ cat /etc/passwd | grep t$

会匹配出所有以t 结尾的行

^与$一起使用

[yb@hadoop101 shells]$ cat /etc/passwd | grep ^abc$

会匹配出所有能完整匹配abc的行。

思考:^$ 匹配什么?匹配空的行。如:

cat hello.sh | grep -n ^$
#可以显示出所有空的行的行号

3)特殊字符:.
. 匹配一个任意的字符,例如

[yb@hadoop101 shells]$ cat /etc/passwd | grep r..t

会匹配包含rabt,rbbt,rxdt,root 等的所有行

4)特殊字符:*
* 不单独使用,他和上一个字符连用,表示匹配上一个字符0 次或多次,例如

[yb@hadoop101 shells]$ cat /etc/passwd | grep ro*t

会匹配rt, rot, root, rooot, roooot 等所有行

思考:.* 匹配什么?任意一个字符,出现任意次即任意的字符串。即模糊匹配:如^a.*yb.*bash$表示以a开头以bash结尾,中间包含yb的所有行。

5)字符区间(中括号):[ ]
[ ] 表示匹配某个范围内的一个字符,例如
[6,8]=[68]------匹配6 或者8
[6,8]*=[68]-*-----匹配6或者8出现任意多次
[0-9]------匹配一个0-9 的数字
[0-9]*------匹配任意长度的数字字符串
[a-z]------匹配一个a-z 之间的字符
[a-z]* ------匹配任意长度的字母字符串
[a-c, e-f]-匹配a-c 或者e-f 之间的任意字符

[yb@hadoop101 shells]$ cat /etc/passwd | grep r[a,b,c]*t

会匹配rt,rat, rbt, rabt, rbact,rabccbaaacbt 等等所有行

#有无,都是一样的意思:会匹配124,134,1234,1324的所有行
[root@vm100 scripts]# echo "123456789023134937024" |grep 1[23]4
123456789023134937024
[root@vm100 scripts]# echo "123456789023134937024" |grep 1[2,3]4
123456789023134937024

在这里插入图片描述

6)特殊字符:
\ 表示转义,并不会单独使用。由于所有特殊字符都有其特定匹配模式,当我们想匹配
某一特殊字符本身时(例如,我想找出所有包含’$’ 的行,如果直接 grep $就会输出所有的行,因为是输出所有以某串字符为结尾的行,但是没有指定是哪串字符,所以就输出所有行)。此时我们就要
将转义字符和特殊字符连用,来表示特殊字符本身,例如

[yb@hadoop101 shells]$ cat /etc/passwd | grep ‘a\$b

就会匹配所有包含a$b 的行。注意需要使用单引号将表达式引起来。

第10 章文本处理工具

10.1 cut

cut 的工作就是“剪”,具体的说就是在文件中负责剪切数据用的。cut 命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段输出。
1)基本用法
cut [选项参数] filename
或结合管道符:… | cut ,表示cut 管道符前面传过来的内容
说明:默认分隔符是制表符 \t
2)选项参数说明
选项参数功能
-f 列号,提取第几列
-d 分隔符,按照指定分隔符分割列,默认是制表符“\t”
-c 按字符进行切割后加n 表示取第几列比如-c 1
3)案例实操
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上面这里是根据空格来切分的,所以我们就要先观察inet前面的空格到底有几个,比对它上面那行的[root@ha可知此处有8个空格,所以算8列,192.168.111.100是在第10 列。(但是在awk中会自动忽略前面的空格,192.168.111.100是在2列)

(1)数据准备

[yb@hadoop101 shells]$ touch cut.txt
[yb@hadoop101 shells]$ vim cut.txt
dong shen
guan zhen
wo wo
lai lai
le le

(2)切割cut.txt 第一列

[yb@hadoop101 shells]$ cut -d " " -f 1 cut.txt
dong
guan
wo
lai
le

(3)切割cut.txt 第二、三列

[yb@hadoop101 shells]$ cut -d " " -f 2,3 cut.txt
shen
zhen
wo
lai
le

(4)在cut.txt 文件中切割出guan

[yb@hadoop101 shells]$ cat cut.txt |grep guan | cut -d " " -f 1
guan

(5)选取系统PATH 变量值,第2 个“:”开始后的所有路径(第2个冒号以后就是第3列):

[yb@hadoop101 shells]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/yb/.local/bin:/
home/yb/bin
[yb@hadoop101 shells]$ echo $PATH | cut -d ":" -f 3-
/usr/local/sbin:/usr/sbin:/home/yb/.local/bin:/home/yb/bin

(6)切割ifconfig 后打印的IP 地址

[yb@hadoop101 shells]$ ifconfig ens33 | grep netmask | cut -d " " -f 10
192.168.111.101

10.2 awk

一个强大的文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。在这里插入图片描述
gawk实际就是awk在GNU里面的具体实现,上图中也可以看出在centos7中使用awk本质上就是使用gawk

1)基本用法
awk [选项参数] ‘/pattern1/{action1} /pattern2/{action2}…’ filename
pattern:表示awk 在数据中查找的内容,就是匹配模式。(正则表达式)
action:在找到匹配内容时所执行的一系列命令
或者… | awk
2)选项参数说明
选项参数功能
-F 指定输入文件分隔符,默认空格
-v 赋值一个用户定义变量
3)案例实操
(1)数据准备

[yb@hadoop101 shells]$ sudo cp /etc/passwd ./

passwd 数据的含义
用户名:密码(加密过后的):用户id:组id:注释:用户家目录:shell 解析器

(2)搜索passwd 文件以root 关键字开头的所有行,并输出该行的第7 列。

[yb@hadoop101 shells]$ awk -F : '/^root/{print $7}' passwd
/bin/bash

在这里插入图片描述

(3)搜索passwd 文件以root 关键字开头的所有行,并输出该行的第1 列和第7 列,
中间以“,”号分割。

[yb@hadoop101 shells]$ awk -F : '/^root/{print $1","$7}' passwd
root,/bin/bash
#逗号要用双引号引起来才表示字符

在这里插入图片描述

注意:只有匹配了pattern 的行才会执行action。
(4)只显示/etc/passwd 的第一列和第七列,以逗号分割,且在所有行前面添加列名user,
shell 在最后一行添加"dahaige,/bin/zuishuai"。

[yb@hadoop101 shells]$ awk -F : 'BEGIN{print "user, shell"} {print $1","$7}
END{print "dahaige,/bin/zuishuai"}' passwd
user, shell
root,/bin/bash
bin,/sbin/nologin
。。。
yb,/bin/bash
dahaige,/bin/zuishuai

注意:BEGIN 在所有数据读取行之前执行;END 在所有数据读取之后执行。

(5)将passwd 文件中的用户id 增加数值1 并输出

[yb@hadoop101 shells]$ awk -v i=1 -F : '{print $3+i}' passwd
1234

4)awk 的内置变量
变量说明
FILENAME 文件名
NR 已读的记录数(行号)
NF 浏览记录的域的个数(切割后,列的个数)

5)案例实操
(1)统计passwd 文件名,每行的行号,每行的列数

[yb@hadoop101 shells]$ awk -F : '{print "filename:" FILENAME ",linenum:"
NR ",col:"NF}' passwd
filename:passwd,linenum:1,col:7
filename:passwd,linenum:2,col:7
filename:passwd,linenum:3,col:7
...

(2)查询ifconfig 命令输出结果中的空行所在的行号

[yb@hadoop101 shells]$ ifconfig | awk '/^$/{print NR}'
9 18
26

(3)切割IP

[yb@hadoop101 shells]$ ifconfig ens33 | awk '/netmask/ {print $2}'
192.168.6.101

在这里插入图片描述

这里是根据空格来切分的,对于是用cut:我们就要先观察inet前面的空格到底有几个,比对它上面那行的[root@ha可知此处有8个空格,所以算8列,192.168.111.100是在第10 列。(但是在awk中会自动忽略前面的空格,192.168.111.100是在2列)

第11 章综合应用案例

11.1 归档文件

实际生产应用中,往往需要对重要数据进行归档备份。
需求:实现一个每天对指定目录归档备份的脚本,输入一个目录名称(末尾不带/),将目录下所有文件按天归档保存,并将归档日期附加在归档文件名上,放在/root/archive 下。
这里用到了归档命令:tar。后面可以加上-c 选项表示归档,加上-z 选项表示同时进行压缩,得到的文件后缀名为.tar.gz
脚本实现如下:

[root@vm100 scripts]# vim daily_archive.sh 

#!/bin/bash

# 首先判断输入参数个数是否为1
if [ $# -ne 1 ]

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

# 定义生成的归档文件名称
FILE=archive_${DIR_NAME}_$DATE.tar.gz #需要归档的文件名称。因为DIR_NAME有下>划线,为了避免混淆,就用{ }括起来
DEST=/root/archive/$FILE #需要归档的文件的存放路径

# 开始归档目录文件

echo "开始归档..."
echo

tar -czf $DEST $DIR_PATH/$DIR_NAME

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

exit

[root@vm100 scripts]# chmod u+x daily_archive.sh 
[root@vm100 scripts]# ll
total 40
-rwxr-xr-x. 1 root root  135 May 30 14:21 add.sh
-rwxr-xr-x. 1 root root  111 Apr  1 10:36 case_test.sh
-rwxr-xr-x. 1 root root   58 Apr  1 10:36 cmd_test.sh
-rwxr--r--. 1 root root 1015 Jun  1 20:29 daily_archive.sh
-rwxr-xr-x. 1 root root  360 Jun  1 19:59 fun_test.sh
-rwxr-xr-x. 1 root root   47 May 30 10:19 hello.sh
-rwxr-xr-x. 1 root root  282 May 30 17:26 if_test.sh
-rwxr-xr-x. 1 root root  168 May 30 20:11 parameter_for_test.sh
-rwxr-xr-x. 1 root root  516 Jun  1 11:29 parameter.sh
-rwxr-xr-x. 1 root root  230 Apr  1 10:36 sum_to.sh
[root@vm100 scripts]# ./daily_archive.sh 
参数个数错误!应该输入一个参数,作为归档目录名
[root@vm100 scripts]# ./daily_archive.sh a b c
参数个数错误!应该输入一个参数,作为归档目录名
[root@vm100 scripts]# ./daily_archive.sh  ../scripts

开始归档...

tar: Removing leading `/' from member names
tar (child): /root/archive/archive_scripts_220601.tar.gz: Cannot open: No such file or directory
tar (child): Error is not recoverable: exiting now
归档出现问题!

[root@vm100 scripts]# mkdir /root/archive
[root@vm100 scripts]# ./daily_archive.sh  ../scripts

开始归档...

tar: Removing leading `/' from member names

归档成功!
归档后的文件为:/root/archive/archive_scripts_220318.tar.gz


#可以不用每次都手动归档,将其加入定时任务中即可:
[root@vm100 scripts]# crontab -l
no crontab for root
[root@vm100 scripts]# crontab -e
no crontab for root - using an empty one
crontab: installing new crontab
#在每天凌晨2点做自动归档。5个数分别代表:分钟,小时,日,月,周几。*代表没有限制。然后是要执行的脚本目录,以及需要归档的文件目录
#打开文档以后写入如下内容。
0 2 * * * /root/scripts/daily_archive.sh  /root/scripts
[root@vm100 scripts]# crontab -l
0 2 * * * /root/scripts/daily_archive.sh  /root/scripts

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值