想学Shell编程?这里有份超级详细攻略请查收

Shell 编程笔记

目录

1. 安装欧拉系统

2. 回顾常用命令

2.1 设置主机名

要设置主机名称,我们需要使用如下的命令格式来完成:

hostnamectl set-hostname 主机名称

例如:将默认的主机名称(localhost)修改为 openEuler

# 修改主机名称
[root@localhost ~]# hostnamectl set-hostname openEuler

# 查看主机名
[root@localhost ~]# hostnamectl hostname
openEuler

# 查看保存主机名的文件内容
[root@localhost ~]# cat /etc/hostname
openEuler
[root@localhost ~]# 

2.2 nmcli命令

我们修改虚拟机的IP地址为 150,需要使用 nmcli 命令

格式:

Usage: nmcli [OPTIONS] OBJECT {
    COMMAND | help }

1)查看网卡名称

[root@localhost ~]# ip a

[root@localhost ~]# ifconfig

2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:4f:96:ec brd ff:ff:ff:ff:ff:ff
    inet 192.168.72.133/24 brd 192.168.72.255 scope global dynamic noprefixroute ens32
       valid_lft 1605sec preferred_lft 1605sec
    inet6 fe80::20c:29ff:fe4f:96ec/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

2)设置IP地址为150

[root@localhost ~]# nmcli c modify ens32 ipv4.addresses 192.168.72.150/24 ipv4.method manual ipv4.dns 114.114.114.114
[root@localhost ~]# nmcli c modify ens32 ipv4.gateway 192.168.72.2
[root@localhost ~]# nmcli c modify ens32 autoconnect yes
[root@localhost ~]# nmcli c up ens32

如果要添加一个新IP而不修改原来的,则执行如下的命令:

[root@openEuler ~]# nmcli c modify ens32 +ipv4.addresses 192.168.72.151/24
[root@openEuler ~]# nmcli c up ens32

2.3 lscpu

这个命令的作用是显示虚拟机的CPU详细信息。

[root@openEuler ~]# lscpu
Architecture:            x86_64
  CPU op-mode(s):        32-bit, 64-bit
  Address sizes:         45 bits physical, 48 bits virtual
  Byte Order:            Little Endian
CPU(s):                  4
  On-line CPU(s) list:   0-3
Vendor ID:               AuthenticAMD
  BIOS Vendor ID:        AuthenticAMD
  Model name:            AMD Ryzen 7 5800H with Radeon Graphics
    BIOS Model name:     AMD Ryzen 7 5800H with Radeon Graphics         
    CPU family:          25
    Model:               80
    Thread(s) per core:  1
    Core(s) per socket:  2
    Socket(s):           2
    Stepping:            0
    BogoMIPS:            6387.99

2.4 重定向

在重定向中涉及到以下三个概述:

  • 标准输入,它是用数字 0 表示,用于接受从终端输入的内容
  • 标准输出,它是用数字 1 表示,用于将内存或文件中的内容输出到终端或文件
  • 标准错误输出,它是用数字 2 表示,将执行命令所产生的错误信息进行输出,可以输入到终端或文件

我在工作中,可以会用到以下方式:

  • 2>&1,表示:将标准输出和标准错误输出到同一个设备上
  • /dev/null,在linux表示一个黑洞

2.4.1 >

这是代表将内容输入到指定文件中,并且是以覆盖的方式来写入内容。

[root@openEuler ~]# cat /etc/passwd | head -5
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@openEuler ~]# cat /etc/passwd | head -5 > passwd
[root@openEuler ~]# ls
anaconda-ks.cfg  hehe.txt  passwd
[root@openEuler ~]# cat passwd 
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@openEuler ~]# cat /etc/passwd | tail -5 > passwd
[root@openEuler ~]# cat passwd 
tcpdump:x:72:72::/:/sbin/nologin
systemd-network:x:987:987:systemd Network Management:/:/usr/sbin/nologin
systemd-resolve:x:986:986:systemd Resolver:/:/usr/sbin/nologin
systemd-timesync:x:985:985:systemd Time Synchronization:/:/usr/sbin/nologin
redhat:x:1000:1000:redhat:/home/redhat:/bin/bash

2.4.2 >>

这种方式表示向文件的末尾追加指定的内容。

[root@openEuler ~]# echo haha >> hehe.txt 
[root@openEuler ~]# cat hehe.txt 
hello world
haha

[root@openEuler ~]# ls >> hehe.txt 
[root@openEuler ~]# cat hehe.txt 
hello world
haha
anaconda-ks.cfg
hehe.txt
passwd

2.4.3 <

这个表示输入重定向,它的主要功能是将一个文件的内容作为命令的输入。这使得我们能够将文件中的数据传递给某个命令,从而让命令以文件内容作为输入进行操作。

使用格式:

command < input_file

示例1:查看文件内容

假设我们有一个名为 data.txt 的文件,里面存储了一些文本数据。我们可以使用 < 符号将文件的内容传递给 cat 命令,以查看文件的内容:

[root@openEuler ~]# cat hehe.txt 
hello world
haha
anaconda-ks.cfg
hehe.txt
passwd

[root@openEuler ~]# cat < hehe.txt 
hello world
haha
anaconda-ks.cfg
hehe.txt
passwd

示例 2 - 统计行数

另一个常见的用法是通过 < 符号将文件传递给 wc 命令,以统计文件的行数、字数和字符数:

[root@openEuler ~]# wc -l hehe.txt 
5 hehe.txt
[root@openEuler ~]# wc -l < hehe.txt 
5

2.4.4 <<

这种方式是将多行文本的内容输入给某个命令。

格式:

command << EOF
这是内容
这也是内容
EOF

使用示例:

[root@openEuler ~]# cat << EOF
> hello
> world
> good
> openEuler
> .
> EOF
hello
world
good
openEuler
.

在上例中,EOF 是我们自定义的分隔符。我们也可以把这个分隔符放到引号:

[root@openEuler ~]# cat << 'EOF'
> redhat
> openlab
> linux
> .
> EOF
redhat
openlab
linux
.

如果希望将多行文本的内容输入到指定的文件中,则可以向如下的方式来实现:

[root@openEuler ~]# cat << EOF > message.txt
> one
> two
> three
> EOF
[root@openEuler ~]# ll
total 16
-rw-------. 1 root root 881 Mar 16 20:10 anaconda-ks.cfg
-rw-r--r--. 1 root root  49 Mar 16 21:07 hehe.txt
-rw-r--r--. 1 root root  14 Mar 17 09:50 message.txt
-rw-r--r--. 1 root root 183 Mar 16 21:03 passwd
[root@openEuler ~]# cat message.txt 
one
two
three
[root@openEuler ~]# cat << EOF >> message.txt 
> hehe.txt
> message.txt
> EOF
[root@openEuler ~]# cat message.txt 
one
two
three
hehe.txt
message.txt

2.4.5 <<<

这个符号是将单行文件内容输入到某个命令中。

格式:

command <<< '单行文本内容'

使用示例:

[root@openEuler ~]# cat <<< 'this is text'
this is text

2.5 wget

wget命令是用于下载网络资源的。它的使用语法:

Usage: wget [OPTION]... [URL]...
常用选项:
-V:查看wget的版本
-b:后台下载
-q:静默下载
-v:显示下载信息
-F:以HTML格式输入文件
-t,--tries=NUMBER:下载的重试次数
-O,--output-document=FILE:将下载的内容写入到文件中
-c,--continue:支持断点续传
-T,  --timeout=SECONDS:下载的超时时间
-w,  --wait=SECONDS:等待时间
--limit-rate=RATE:限制下载速度

使用示例:

# 查看版本
[root@openEuler ~]# wget -V
GNU Wget 1.21.2 built on linux-gnu.

# 下载文件
[root@openEuler ~]# wget https://pm.myapp.com/invc/xfspeed/qqpcmgr/download/QQPCDownload320059.exe

# 限制下载速度
[root@openEuler ~]# wget https://pm.myapp.com/invc/xfspeed/qqpcmgr/download/QQPCDownload320059.exe
 --limit-rate=10K

# 下载后指定文件名称
[root@openEuler ~]# wget https://pm.myapp.com/invc/xfspeed/qqpcmgr/download/QQPCDownload320059.exe -O qq.exe

# 后台下载
[root@openEuler ~]# wget https://pm.myapp.com/invc/xfspeed/qqpcmgr/download/QQPCDownload320059.exe -O qq2.exe -b

2.6 watch

linux命令watch是周期性的用来执行某命令,并把某命令执行结果输出到屏幕上。使用watch命令,可以周期性的监测并输出某命令的执行结果到屏幕上,省得手动一遍一遍运行某命令,提高工作效率。

watch常用参数

参数 说明
-h watch帮助文档
-n 设置watch时间间隔,默认为2s
-d 高亮显示变化的区域
-t 不显示顶部的时间间隔信息

示例:

# 第隔 4s 执行一次 ls 命令
[root@openEuler ~]# watch -n 4 ls

2.7 xargs

xargs 命令是给其他命令传递参数的一个过滤器,也是组合多个命令的一个工具。它擅长将标准输入数据转换成命令行参数,xargs 能够处理管道或者 stdin 并将其转换成特定命令的命令参数。

格式:

xargs [选项] [命令]

选项:

-I:用于指定替换字符串,将输入数据中的特定字符串替换为命令行参数。
-n:用于指定每次执行命令的参数个数。
-t:用于打印执行的命令。
-p:用于提示用户确认是否执行命令。
-r:当标准输入为空时,不执行命令。

示例:

# 准备数据
[root@openEuler ~]# cat << EOF > test.txt
> 
> a b c d e f g
> h i j k l m n
> o p q
> r s t
> u v w x y z
> 
> EOF
[root@openEuler ~]# 
[root@openEuler ~]# cat test.txt 

a b c d e f g
h i j k l m n
o p q
r s t
u v w x y z

# 多行输入单行输出
[root@openEuler ~]# cat test.txt | xargs
a b c d e f g h i j k l m n o p q r s t u v w x y z

#使用 -n 进行多行输出,-n 选项多行输出:
[root@openEuler ~]# cat test.txt | xargs -n3
a b c
d e f
g h i
j k l
m n o
p q r
s t u
v w x
y z

#使用 -d 分割输入
#-d 选项可以自定义一个定界符:
[root@openEuler ~]# echo "nameXnameXnameXname" | xargs -dX
name name name name

#结合 -n 选项使用:
[root@openEuler ~]# echo "nameXnameXnameXname" | xargs -dX -n1
name
name
name
name

#结合 -I 选项
#xargs 的一个选项 -I,使用 -I 指定一个替换字符串{},这个字符串在 xargs 扩展时会被替换掉,当 -I 与 xargs 结合使用,每一个参数命令都会被执行一次:
cat arg.txt | xargs -I {
   } ./sk.sh -p {
   } -l

-p aaa -l
-p bbb -l
-p ccc -l

#复制当胶目录下所有.txt文件到当前目录下d1目录中:
[root@openEuler ~]# mkdir d1
[root@openEuler ~]# ll
total 24
-rw-------. 1 root root  881 Mar 16 20:10 anaconda-ks.cfg
drwxr-xr-x. 2 root root 4096 Mar 17 10:28 d1
-rw-r--r--. 1 root root   49 Mar 16 21:07 hehe.txt
-rw-r--r--. 1 root root   35 Mar 17 09:51 message.txt
-rw-r--r--. 1 root root  183 Mar 16 21:03 passwd
-rw-r--r--. 1 root root   54 Mar 17 10:21 test.txt
[root@openEuler ~]# ls *.txt
hehe.txt  message.txt  test.txt
[root@openEuler ~]# ls *.txt | xargs -I cp {} d1
xargs: {
   }: No such file or directory
[root@openEuler ~]# ls *.txt | xargs -n 1 -I {} cp {} d1/
[root@openEuler ~]# ll
total 24
-rw-------. 1 root root  881 Mar 16 20:10 anaconda-ks.cfg
drwxr-xr-x. 2 root root 4096 Mar 17 10:29 d1
-rw-r--r--. 1 root root   49 Mar 16 21:07 hehe.txt
-rw-r--r--. 1 root root   35 Mar 17 09:51 message.txt
-rw-r--r--. 1 root root  183 Mar 16 21:03 passwd
-rw-r--r--. 1 root root   54 Mar 17 10:21 test.txt
[root@openEuler ~]# tree d1
d1
├── hehe.txt
├── message.txt
└── test.txt

0 directories, 3 files

2.8 cron

cron 是 Linux 系统中后台进程模式周期性执行命令或指定程序的服务软件名。Linux 系统启动后,cron 软件便会启动,对应的进程名字叫 crond,默认是定期(每分钟检查一次)检查系统中是否有需要执行的任务计划。如果有则按计划进行,好比我们平时用的闹钟。

crond 服务除了会在工作时查看 /var/spool/cron 文件夹下的定时任务文件以外,还会查看 /etc/cron.d 目录以及 /etc/anacrontab 下面的文件内容,里面存放每天、每周、每月需要执行的系统任务。

[root@openEuler ~]# ls /var/spool/cron/
[root@openEuler ~]# ls -l /etc/ | grep cron*
-rw-r--r--.  1 root root      541 Dec 28 13:43 anacrontab
-rw-------.  1 root root        0 Mar 16 20:17 cron.allow
drwx------.  2 root root     4096 Mar 16 20:07 cron.d
drwx------.  2 root root     4096 Mar 16 20:08 cron.daily
drwx------.  2 root root     4096 Mar 16 20:07 cron.hourly
drwx------.  2 root root     4096 Dec 16 23:57 cron.monthly
-rw-------.  1 root root      451 Dec 16 23:57 crontab
drwx------.  2 root root     4096 Dec 16 23:57 cron.weekly

系统定时任务配置文件 /etc/crontab

[root@openEuler ~]# vim /etc/crontab 


# 文件内容如下
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name  command to be executed

crontab命令被用来提交和管理用户的需要周期性执行的任务,与 windows 下的计划任务类似。

参数 解释 示例
-l list 查看定时任务 crontab -l
-e edit 编辑定时任务,建议手动编辑 crontab -e
-i 删除定时任务,提示用户确认删除,避免出错 crontab -i
-r 删除定时任务,移除/var/spool/cron/username文件 crontab -r
-u user 指定用户执行任务,root 可以管理普通用户计划任务 crontab -u redhat -l

使用格式:

*  *  *  * *
分 时 日 月 周

0 * * * *	每小时执行,每小时的整点执行
1 2 * * 4	每周执行,每周四的凌晨2点1分执行
1 2 3 * *	每月执行,每月的3号的凌晨2点1分执行
1 2 3 4 *	每年执行,每年的4月3号的凌晨2点1分执行
1 2 * * 3,5	每周3和周5的2点1分执行
* 13,14 * * 6,0	每周六、周日下午1点和2点的每一分钟都执行
0 9-18 * * 1-5	周一到周五每天早上9点到下午6点的每一个整点
*/10 * * * *	每隔10分钟执行一次任务

注意:如果没法整除,定时任务则没意义,可以自定制脚本控制频率

使用示例:

1. 每分钟执行命令
* * * * * cmd

2. 每天凌晨3点半和12点半执行脚本
30 3,12 * * * cmd

3. 每隔6小时,相当于6,12,18,24点半执行脚本
30 */6 * * * cmd
30 6,12,18,24 * * * cmd

4. 30代表半点,8-18/2表示早上8点到下午18点之间每隔2小时执行脚本
30 8-18/2 * * * cmd

5. 每天晚上9点30重启nginx
30 21 * * * /opt/nginx/sbin/nginx --restart

6. 每月1和10号凌晨4点45执行脚本
45 4 1,10 * * cmd

7. 每周六和周日凌晨1点10分执行命令
10 1 * * 6,7 cmd
10 1 * * 6,0 cmd

8. 每天18点到23点之间,每隔30分钟执行一次
*/30 18-23 * * * cmd
0,30 18-23 * * * cmd

9. 每隔一小时执行一次
* */1 * * * cmd

10. 4月份的周一到周三的上午11点执行脚本
* 11 * 4 1-3 cmd

11. 每天早上7点到上午11点,每2小时运行cmd命令
* 7-11/2 * * * cmd

12. 每天6点执行脚本
0 6 * * * cmd

13. 每周六凌晨4点执行
* 4 * * 6 cmd

14. 每周六凌晨4点05执行
5 4 * * 6 cmd

15. 每天8:40执行
40 8 * * * cmd

16. 在每天10:31开始,每隔2小时重复一次
31 10/2 * * * cmd

17. 每周一到周五2:00执行
0 2 * * 1-5 cmd

18. 每周一到周五8:00,每周一到周五9:00执行
0 8,9 * * 1-5 cmd

19. 每天10:00,16:00执行
0 10,16 * * * cmd

3. Shell脚本基础

3.1 Shell的基本元素

声明:使用那一种解释器来解释并执行当前的脚本。#!/bin/bash

命令:可执行的语句,实现程序的功能。

注释:单行注释,使用 # 号来进行注释,另一种是多行注释 :<<BLOCK 注释内容 BLOCK

赋予脚本可执行权限

3.2 Shell脚本规范

  1. 脚本名称尽量做见名知意
  2. 在脚本的开头指定解释器
  3. 在开头增加版权信息
  4. 尽量使用系统命令,而少使用管道
  5. 尽量不要使用中文注释
  6. 代码注重缩进

3.3 Shell脚本编写方式

  1. 交互式执行

    [root@openEuler ~]# for name in `ls /etc`
    > do
    > echo $name
    > done
    
  2. 作为程序文件执行(推荐使用)

    [root@openEuler ~]# vim for_test.sh
    
    #!/bin/bash
    
    echo $USER
    

3.4 Shell脚本执行方式

  1. bash for_test.sh 命令来执行,它会产生一个子 Shell,然后在子 Shell 中运行脚本,执行完后回去父Shell。
  2. sh for_test.sh 命令来执行,它也会产生一个子 Shell,然后在子 Shell 中运行脚本,执行完后回去父Shell。
  3. ./for_test.sh 命令来执行,它也会产生一个子Shell,不同点在于它需要有 x 权限。
  4. . for_test.sh 命令来执行,使用是文件中定义的解释器,不会产生子 Shell,它是在当前的环境中执行的。
  5. source for_test.sh命令来执行,它的作用与 . 执行一样
[root@openEuler ~]# sh for_test.sh 
root
[root@openEuler ~]# ll
total 32
-rw-------. 1 root root  881 Mar 16 20:10 anaconda-ks.cfg
drwxr-xr-x. 2 root root 4096 Mar 17 10:29 d1
-rw-r--r--. 1 root root   24 Mar 23 14:32 for_test.sh
-rw-r--r--. 1 root root   49 Mar 16 21:07 hehe.txt
-rw-r--r--. 1 root root   35 Mar 17 09:51 message.txt
-rwxr-xr-x. 1 root root   26 Mar 17 11:18 my.sh
-rw-r--r--. 1 root root  183 Mar 16 21:03 passwd
-rw-r--r--. 1 root root   54 Mar 17 10:21 test.txt
[root@openEuler ~]# ./for_test.sh
-bash: ./for_test.sh: Permission denied
[root@openEuler ~]# chmod a+x for_test.sh 
[root@openEuler ~]# ./for_test.sh 
root
[root@openEuler ~]# . for_test.sh 
root
[root@openEuler ~]# source for_test.sh 
root

3.5 Shell退出状态

在 Linux 中执行命令后,会有一个状态,如果值为 0 表示之前执行的命令是正常执行的,如果是非0则表示前一条命令执行是有错误发生。

[root@openEuler ~]# source for_test.sh 
root
[root@openEuler ~]# echo $?
0
[root@openEuler ~]# source for_test.sh1 
-bash: for_test.sh1: No such file or directory
[root@openEuler ~]# echo $?
1

4. 变量和引用

4.1 什么是变量

变量就是程序设计中一个可以变化的量。它会在内存中开辟一个空间,变量的名称引用是这个空间对应的地址,而这个地址中存储的就是变量的值。

4.2 变量的命名

在 Shell 中变量的名称可以由字母、数字和下划线组成,但是数字不能开头。原则上对变量的长度没有限制,但是一般不推荐变量名太长。尽量做到变量名称见名知意。

4.3 变量的作用范围

在 Shell 中命令的作用范围分为全局变量和局部变量,全局变量也叫系统变量,它在整个系统都可以用。而局部变量是需要在特定的环境中才可以使用的。

4.3.1 局部变量

局部变量也叫用户变量,或者叫临时变量。它只能在当前用户所在的环境中使用,或者在当前的会话中使用。

[root@openEuler ~]# name=lisi
[root@openEuler ~]# echo $name
lisi
[root@openEuler ~]# echo ${name}
lisi

# 产生一个子Shell环境
[root@openEuler ~]# bash
[root@openEuler ~]# echo $name

# 退出到父Shell环境
[root@openEuler ~]# exit
exit
[root@openEuler ~]# echo ${name}
lisi

4.3.2 全局变量

全局变量也叫系统变量,也可以称为永久变量。它是不区分用户环境的,对整个系统都有效。它需要定义在 /etc/profile 或者 /etc/bashrc 文件中通过 export 来导出。

我们在 /etc/profile 中定义一个变量,编写这个文件,在这个文件的最后添加如下内容:

[root@openEuler ~]# vim /etc/profile


export MyPath=/root

然后保存退出,然后测试是否能获取到定义的变量

[root@openEuler ~]# echo $MyPath

[root@openEuler ~]# . /etc/profile

[root@openEuler ~]# echo $MyPath
/root

# 切换用户及环境后再测试
[root@openEuler ~]# su - redhat
[redhat@openEuler ~]$ echo $MyPath
/root

[redhat@openEuler ~]$ exit
logout
[root@openEuler ~]# bash
[root@openEuler ~]# echo $MyPath
/root
[root@openEuler ~]# exit
exit

4.4 删除变量

当变量不再使用时,我们就需要把它删除,从而可以节省内存空间。

要删除变量就需要使用 unset 命令。它的语法为:

unset 变量名

使用示例:我们删除之前创建的 name 变量。

[root@openEuler ~]# echo $name
lisi
[root@openEuler ~]# unset name
[root@openEuler ~]# echo $name

[root@openEuler ~]# 

面试题:如下代码输出的结果是什么?

[root@openEuler ~]# cat test.sh
user1=`whoami`
[root@openEuler ~]# sh test.sh
[root@openEuler ~]# echo $user1

A. 当前用户
B. root
C. 空
D. 报错

4.5 变量的类型

Shell 是一种动态类型语言,也是一种弱类型的语言。所以在定义变量时,我们无须指定具体存放的值是什么类型(如:整数、小数、字符串等)。

但是在 Shell,变量也存在类型,它有以下几种类型:

  • 自定义变量
  • 环境变量
  • 只读变量
  • 位置变量
  • 预定义变量

4.5.1 自定义变量

在 Shell 中,通常情况下都是用户在使用时直接定义的变量,而无须先进行定义。

1)自定义变量的格式:
变量名=变量值

注意:

  1. 等号两边不能有空格
  2. 变量值如果是数字一般不加引号,如果是字符串推荐加引号;如果值包含有特殊字符或空格就必须要有引号
  3. 引号可以是以下几种:
    1. 单引号:被单引号包含的内容会原样输出
    2. 双引号:被双引号包含的内容会把变量的值替换后再输出
    3. 反引号:被反引号包含的命令执行的结果赋值给变量
2)查看变量的值

在 Shell 中查看变量的值有以下几种:

  • echo $变量名
  • echo ${变量名}
  • set 查看系统中所有变量
  • env 来查看系统环境变量
  • declare 来查看输出的所有变量、函数等。

使用示例:

[root@openEuler ~]# a=1
[root@openEuler ~]# echo $a
1
[root@openEuler ~]# echo ${a}
1
[root@openEuler ~]# ts=cs1
[root@openEuler ~]# echo $ts
cs1
[root@openEuler ~]# b = "hello"
-bash: b: command not found
[root@openEuler ~]# b ="hello"
-bash: b: command not found
[root@openEuler ~]# b= "hello"
-bash: hello: command not found
[root@openEuler ~]# b="hello"
[root@openEuler ~]# b='world'
[root@openEuler ~]# echo $b
world
[root@openEuler ~]# b=`pwd`
[root@openEuler ~]# echo $b
/root
[root@openEuler ~]# 

[root@openEuler ~]# env
SHELL=/bin/bash
HISTCONTROL=ignoredups
HISTSIZE=1000
HOSTNAME=openEuler
MyPath=/root
PWD=/root
LOGNAME=root
MOTD_SHOWN=pam
HOME=/root
LANG=en_US.UTF-8

对于单引号和双引号的区别:

[root@openEuler ~]# age=18
[root@openEuler ~]# name=list
[root@openEuler ~]# echo "$name,$age"
list,18
[root@openEuler ~]# echo '$name,$age'
$name,$age
[root@openEuler ~]# echo "\$name"
$name

3)使用declare来定义变量

格式如下:

declare attribute variable

attribute 它可以是 +/- 来定义,如果是 - 表示为这个属性设置值,如果是 + 表示取消此属性
有以下属性:
-p:表示所有变量的值
-i:将变量定义为整数,如果不能转换为整数则为 0
-r:将变量声明为只读变量
-a:将变量声明为数组

使用示例:

# 使用 -i 属性来声明定义的变量 n 的类型是一个整数,如果n的值不能转换为整数,则以0填充
[root@openEuler ~]# declare -i n
[root@openEuler ~]# n=5
[root@openEuler ~]# n=a
[root@openEuler ~]# echo $n
0
[root@openEuler ~]# n=4
[root@openEuler ~]# echo $n
4

# 使用 -r 属性来声明变量为只读的变量,对于只读变量来说,只能赋值一次,即它的值设置好后,就不能发生变量。
[root@openEuler ~]# declare -r name
[root@openEuler ~]# name=wangwu
-bash: name: readonly variable
[root@openEuler ~]# echo $name
list
[root@openEuler ~]# x=3
[root@openEuler ~]# declare -r x
[root@openEuler ~]# x=5
-bash: x: readonly variable


# 使用 -a 属性来声明变量是一个数组,数组是通过下标来设置或获取数据的,下标是从0开始,最大的下标是数组的长度 - 1。如果希望获取数组中所有的元素(值),可以使用 `数组名[@]` 的形式来获取
[root@openEuler ~]# declare -a arr
[root@openEuler ~]# arr[0]="hello"
[root@openEuler ~]# arr[1]="world"
[root@openEuler ~]# arr[2]="shell"
[root@openEuler ~]# echo $arr[0]
hello[0]
[root@openEuler ~]# echo ${arr[0]}
hello
[root@openEuler ~]# echo ${arr[2]}
shell
[root@openEuler ~]# echo ${arr[5]}

[root@openEuler ~]# echo ${arr[@]}
hello world shell
4)通过交互定义变量

在编写 Shell 脚本时,我们会用到与用户进行交互,将用户输入的值赋予我们定义的变量。此时我们可以使用 read 命令来实现。它的使用格式如下:

read -p "输入提示信息" 变量名称

使用示例:

[root@openEuler ~]# read -p 'please input your number:' num
please input your number:18
[root@openEuler ~]# echo $num
18
[root@openEuler ~]# 

除了这种在命令行中使用外,还可以在脚本中使用。格式如下:

[root@openEuler ~]# vim my_read.sh
[root@openEuler ~]# cat my_read.sh

#!/bin/bash
echo 'please input your number:'
read num
echo $num

[root@openEuler ~]# ll
total 40
-rw-------. 1 root root  881 Mar 16 20:10 anaconda-ks.cfg
drwxr-xr-x. 2 root root 4096 Mar 17 10:29 d1
-rwxr-xr-x. 1 root root   24 Mar 23 14:32 for_test.sh
-rw-r--r--. 1 root root   49 Mar 16 21:07 hehe.txt
-rw-r--r--. 1 root root   35 Mar 17 09:51 message.txt
-rw-r--r--. 1 root root   69 Mar 23 16:12 my_read.sh
-rwxr-xr-x. 1 root root   26 Mar 17 11:18 my.sh
-rw-r--r--. 1 root root  183 Mar 16 21:03 passwd
-rw-r--r--. 1 root root   34 Mar 23 15:33 test.sh
-rw-r--r--. 1 root root   54 Mar 17 10:21 test.txt
[root@openEuler ~]# bash my_read.sh 
please input your number:
20
20

4.5.2 环境变量

在 Shell 中环境变量分为系统环境变量和用户环境变量。系统变量的定义参数前变量范围中的内容。而用户环境变量我们可以用户的家目录下的 ~/.bash_profile 文件或 ~/.bashrc 文件中定义的变量。

在 Linux 中给我们内置了很多的环境变量,如:

# 执行命令时搜索的路径,以冒号进行分隔
[root@openEuler ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/

# 当前登录的用户名
[root@openEuler ~]# echo $USER
root

# 当前登录用户的家目录
[root@openEuler ~]# echo $HOME
/root

# 定义在命令模式下可以使用的命令行的长度
[root@openEuler ~]# echo $COLUMNS
156

# 命令存放的历史文件
[root@openEuler ~]# echo $HISTFILE
/root/.bash_history

其实,以上的这些系统变量我们可以使用 env 命令来查看:

[root@openEuler ~]# env
SHELL=/bin/bash
HISTCONTROL=ignoredups
HISTSIZE=1000
HOSTNAME=openEuler
MyPath=/root
PWD=/root
LOGNAME=root
MOTD_SHOWN=pam
HOME=/root
LANG=en_US.UTF-8
user1=root
SSH_CONNECTION=192.168.72.1 8175 192.168.72.150 22
SELINUX_ROLE_REQUESTED=
TERM=xterm
USER=root
SELINUX_USE_CURRENT_RANGE=
SHLVL=1
SSH_CLIENT=192.168.72.1 8175 22
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
SELINUX_LEVEL_REQUESTED=
MAIL=/var/spool/mail/root
SSH_TTY=/dev/pts/0
_=/usr/bin/env

4.5.3 只读变量

如果希望定义的变量在程序的执行过程中不会发生变量,此时就可以声明为只读变量。声明只读变量有两种方式:

  • declare -r 变量名称
  • readonly 变量名称

使用示例:

[root@openEuler ~]# n=1
[root@openEuler ~]# n=2
[root@openEuler ~]# readonly n
[root@openEuler ~]# n=3
-bash: n: readonly variable

当然,除我们先声明变量再变为只读外,也可以在声明的时候就定义为只读。

[root@openEuler ~]# readonly m=5
[root@openEuler ~]# m=6
-bash: m: readonly variable
[root@openEuler ~]# echo $m
5

对于只读变量来说,不能使用 unset 来删除。

4.5.4 位置变量

在很情况下,Shell 脚本执行时是需要接收用户输入的参数的,这时就需要使用到位置变量。

1)特殊变量
$#:表示参数的个数
$n:其中n表示大于0的数字,表示第 n 个参数
$0:表示这个被执行的脚本名称
$*:表示获取所有的参数列表
$@:表示获取所有的参数列表

使用示例:

# 编写一个脚本
[root@openEuler ~]# vim t1.sh
# 查看脚本内容
[root@openEuler ~]# cat t1.sh
#!/bin/bash

echo "total parameters: $#"
echo "first parameter: $1"
echo "second parameter: $2"
echo "filename is: $0"
echo "all arguments: $*"
echo "all arguments: $@"

# 运行脚本
[root@openEuler ~]# bash t1.sh python shell golang html
total parameters: 4
first parameter: python
second parameter: shell
filename is: t1.sh
all arguments: python shell golang html
all arguments: python shell golang html

2)$*$@的区别
[root@openEuler ~]# set -- "hello" "world" "shell"
[root@openEuler ~]# echo $*
hello world shell
[root@openEuler ~]# echo $@
hello world shell
[root@openEuler ~]# for fname in "$@"; do echo $fname; done
hello
world
shell
[root@openEuler ~]# for fname in "$*"; do echo $fname; done
hello world shell

从上面的输出结果可以发现 $*$@的异同如下:

  1. $*$@ 都可以获取到所有的参数列表,如果不加引号,它们没区别,如果加了引号区别如下:
  2. $@它是将参数以 “参数1” “参数2” 获取的,而 $*则是将参数以"参数1 参数2"的方式获取的
3)$? 执行结果状态

当脚本命令执行后,会有一个执行后的状态值,如果这个值为 0 则表示前一条命令执行成功,否则表示执行不成功,即有错误。

[root@openEuler ~]# cat t2.sh
cat: t2.sh: No such file or directory
[root@openEuler ~]# echo $?
1
[root@openEuler ~]# cat t1.sh
#!/bin/bash

echo "total parameters $#"
echo "first parameter $1"
echo "second parameter $2"
echo "filename is $0"
echo "all arguments $*"
echo "all arguments $@"
[root@openEuler ~]# echo $?
0

4)特殊状态变量

在 Shell 特殊状态变量有以下几个:

$$:返回脚本进程的PID
$!:获取上一个在后台的工作进程的PID
$_:保存的是之前所执行命令的最后一个参数

以上三个都不常用,大家了解即可。

[root@openEuler ~]# vim t2.sh
[root@openEuler ~]# cat t2.sh
#!/bin/bash

[ $# -ne 2 ] && {
   
	echo "must be two arguments"
	exit 3
}
echo ok
echo "current shell pid: $$"		# 输出当前脚本执行时产生的 PID 值

nohup ping www.baidu.com & 1>/dev/null		# 将 ping 命令的执行放到后台运行,并且不输出任何信息

echo $!		# 输出上一个后台运行的命令的 PID 值

将脚本编写好后,通过如下的方式来执行,从而得到如下的结果。

[root@openEuler ~]# bash t2.sh
must be two arguments

[root@openEuler ~]# bash t2.sh a b
ok
current shell pid: 2540		# 脚本运行的PID
2541						# ping命令运行的PID
nohup: appending output to 'nohup.out'
[root@openEuler ~]# ps -ef | grep ping			# 查看ping 进程
root        2541       1  0 17:10 pts/0    00:00:00 ping www.baidu.com
root        2543    1666  0 17:10 pts/0    00:00:00 grep --color=auto ping
[root@openEuler ~]# echo $_		# 输出上一次命令的最后一个参数
b

4.6 变量的特殊用法

在实际工作中,对变量的值还会有一些特殊的用法,例如对变量的值里德截取、替换、删除等。

要想实现这些功能,我们需要使用如下的格式:

${变量}					获取变量的值
${#变量}					返回变量的长度,即字符串的长度
${变量:start}				返回变量从start开始截取到变量最后,它是从 0 开始
${变量:start:length}		截取变量的值中从 start 开始,到 length 长度的内容
${变量#word}				将变量开头删除最短匹配的 word 子串
${变量##word}				将变量开头删除最长匹配的 word 子串
${变量%word}				从变量结尾删除最短的 word
${变量%%word}				从变量结尾删除最长的 word
${变量/parttern/string}	使用string代替第一个匹配的 parttern
${变量//parttern/string}	使用string代替所有匹配的 parttern

4.6.1 获取变量

${变量}					获取变量的值
${
   #变量}					返回变量的长度,即字符串的长度

使用示例:

[root@openEuler ~]# name="I am openEuler"
[root@openEuler ~]# echo ${name}
I am openEuler
[root@openEuler ~]# echo ${#name}
14

4.6.2 变量值截取

${变量:start}				返回变量从start开始截取到变量最后,它是从 0 开始
${变量:start:length}		截取变量的值中从 start 开始,到 length 长度的内容

使用示例:

[root@openEuler ~]# name="I am openEuler"
[root@openEuler ~]# echo ${name:2}
am openEuler
[root@openEuler ~]# echo ${name:2:5}
am op
[root@openEuler ~]# 

4.6.3 字符串删除

${变量#word}				将变量开头删除最短匹配的 word 子串
${变量##word}				将变量开头删除最长匹配的 word 子串
${变量%word}				从变量结尾删除最短的 word
${变量%%word}				从变量结尾删除最长的 word

使用示例:

[root@openEuler ~]# name="abcABC123ABCabc"
[root@openEuler ~]# echo ${name}
abcABC123ABCabc
[root@openEuler ~]# echo ${name#a*c}		# 匹配最短,它是从前往后删除
ABC123ABCabc
[root@openEuler ~]# echo ${name##a*c}		# 匹配最长,它是从前往后删除


[root@openEuler ~]# unset name
[root@openEuler ~]# name="abcABC123ABCabc"
[root@openEuler ~]# echo ${name}
abcABC123ABCabc
[root@openEuler ~]# echo ${name%a*c}		# 匹配最短,从后往前删除
abcABC123ABC
[root@openE
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值