为何网站打不开,网页界面设计的用途有,曹鹏wordpress,给人建设网站能赚钱吗本章主要介绍如何使用bash写脚本。 了解通配符 了解变量 了解返回值和数值运算 数值的对比 判断语句 循环语句 grep的用法是“grep 关键字 file”#xff0c;意思是从file中过滤出含有关键字的行。 例如#xff0c;grep root /var/log/messages#xff0c;意思是从/var/log/…本章主要介绍如何使用bash写脚本。 了解通配符 了解变量 了解返回值和数值运算 数值的对比 判断语句 循环语句 grep的用法是“grep 关键字 file”意思是从file中过滤出含有关键字的行。 例如grep root /var/log/messages意思是从/var/log/messages 中过滤出含有root的行。这里很明确的是过滤含有“root”的行。 如果想在/var/log/messages 中过滤出含有IP地址的行呢?IP地址就是一类字符例如 1.1.1.1是一个IP192.168.26.100也是一个IP那么用什么能表示出来这一类字符呢? 不管是通配符还是正则表达式都是为了模糊匹配为了匹配某一类内容而不是具体的 某个关键字。通配符一般用在shell语言中正则表达式一般用在其他语言中。 不管是通配符还是正则表达式主要是理解它们的元字符,然后用元字符来组合成我们想 要的那一类字符,本章主要讲解通配符的使用。 像我们平时说的张某某这个某就是一个元字符不是一个定值。指的是姓张名字含有2个字。张某某可能匹配到张二狗也可能匹配到张阿猫但是无法匹配到李阿三也匹配不了张三因为张某某匹配的是姓名为3个字的但是张三这个姓名只有2个字。 如果说有一个人姓“张”名“某”那么需要匹配“张某”这个人而不是要匹配张三、 张四,可以用张\某某前加个“\”表示转义的意思。
1 通配符 通配符一般用在shell语言中,通配符中常见的元字符如下。 1[]匹配一个字符,匹配的是出现在中括号中的字符。 2[abc]匹配一个字符且只能是a或b或c。 3[a-z]“-”有特殊意义表示“到”的意思这里表示a~z即匹配任一字母。 4[0-9]表示匹配任一数字。 如果想去除含有特殊意义的字符前面加“\”表示转义即去除此字符的特殊意义 5[a\-z]这里的“-”就没有“到”的意思了匹配的是“a”或“-”或“z”这三个 中的一个。 如果想表示“除了”的意思则在第一个中括号后面加“!”或“^”。 6[!a-z]、[^a-z]表示除字母外的其他字符。 7?表示一个任意字符这里强调是一个不是0个也不是多个但不能匹配表示隐藏 文件的点。 8*表示任意多个任意字符可以是0个也可以是1个或多个但不能匹配表示隐藏 文件的点。 先创建目录xx并在目录中创建如下几个测试文件命令如下。
[rootredhat8 ~]# mkdir xx
[rootredhat8 ~]# cd xx
[rootredhat8 xx]# touch 1_aa aa11 Aa11 _aaa aa.txt f1aa u_12找出首字符是字母、第二个字符是数字的文件命令如下。
[rootredhat8 xx]# ls [a-z][1-9]*
f1aa找出首字符是字母、第二个字符不是数字的文件命令如下。
[rootredhat8 xx]# ls [a-z][^1-9]*
aa11 Aa11 aa.txt u_12找出首字符不是字母、第二个字符不是数字的文件,命令如下。
[rootredhat8 xx]# ls [^a-z][^1-9]*
1_aa _aaa可以看到找出来的文件完全符合我们的需求。下面找出首字符是大写字母、第二个字符 是非数字的文件命令如下。
[rootredhat8 xx]# ls
1_aa aa11 Aa11 _aaa aa.txt f1aa u_12
[rootredhat8 xx]# ls [A-Z][!1-9]*
Aa11 u_12可以看到首字符是大写字母的文件列出来了首字符是小写字母的文件有的列出来了, 有的没有列出来所以[a-z]或[A-Z]有时并不精确。如果要更精确可以用如下元字符。 1[[:upper:]]纯大写。 2[[:lower:]]小写。 3[[:alpha:]]字母。 4[[:alnum:]字母和数字。 5[[:digit:]]数字。 列出首字符是小写字母、第二个字符是数字的文件命令如下。
[rootredhat8 xx]# ls [[:lower:]][0-9]*
f1aa列出首字符是大写字母、第二个字符是数字或字母的文件命令如下。
[rootredhat8 xx]# ls [[:upper:]][[:alnum:]]*
Aa11如果想在yum 源中列出所有以 vsftpd开头的包可以用如下命令。
[rootredhat8 ~]# yum list vsftpd*
正在更新 Subscription Management 软件仓库。
无法读取客户身份本系统尚未在权利服务器中注册。可使用 subscription-manager 进行注册。上次元数据过期检查21:39:27 前执行于 2023年12月14日 星期四 12时09分33秒。
可安装的软件包
vsftpd.x86_64 3.0.3-34.el8 aa在当前目录中创建一个文件vsftpdxxx命令如下。
[rootredhat8 ~]# touch vsftpdxxx然后再执行yum list vsftpd*命令命令如下。
[rootredhat8 ~]# yum list vsftpd*
正在更新 Subscription Management 软件仓库。
无法读取客户身份本系统尚未在权利服务器中注册。可使用 subscription-manager 进行注册。上次元数据过期检查21:40:00 前执行于 2023年12月14日 星期四 12时09分33秒。
错误没有匹配的软件包可以列出此处显示没有匹配的包为什么呢?因为yum是 bash的一个子进程vsftpd在 bash中首先被解析成了vsftpdxxx然后再经过yum。所以本质上执行的是yum list vsftpdxx命令而yum源中是没有vsftpdxxx 这个包的所以报错。 为了防止 bash 对这里的*进行解析可以加上转义符“\”所以下面的命令是正确的。
[rootredhat8 ~]# yum list vsftpd\*
正在更新 Subscription Management 软件仓库。
无法读取客户身份本系统尚未在权利服务器中注册。可使用 subscription-manager 进行注册。上次元数据过期检查21:40:11 前执行于 2023年12月14日 星期四 12时09分33秒。
可安装的软件包
vsftpd.x86_64 3.0.3-34.el8
2 变量 所谓变量指的是可变的值并非具体的值。例如我自己嘴中发出的“我”指的是我自己张三嘴中发出的“我”指的是张三那么这个“我”就是一个变量。 变量可以分为本地变量、环境变量、位置变量和预定义变量。
2.1 本地变量 定义本地变量的格式如下。 定义变量有以下几点需要注意。 1变量名可以包含_、数字、大小写字母但不能以数字开头。 2“”两边不要有空格。 3“值”如果含有空格要使用单引号或双引号引起来。 4定义变量时变量名前是不需要加$的引用变量时需要在变量名前加$。 本章实验都放在~/yy中练习命令如下。
[rootredhat8 ~]# cd
[rootredhat8 ~]# mkdir yy ; cd yy下面开始练习定义变量命令如下。
[rootredhat8 yy]# 1aa123
bash: 1aa123: 未找到命令...这里定义变量不正确因为变量名不能以数字开头命令如下。
[rootredhat8 yy]# aa-1123
bash: aa-1123: 未找到命令...这里定义变量不正确因为变量名只能是字母、数字、下划线的组合命令如下。
[rootredhat8 yy]# aa 123
bash: aa: 未找到命令...这里的错误是因为等号左边有空格。
[rootredhat8 yy]# aa1 2
bash: 2: 未找到命令...这里的错误是因为“值”部分有空格没有用引号引起来。
[rootredhat8 yy]# aa123
[rootredhat8 yy]# 这里正确地定义了一个变量。 在使用本地变量时,变量名前需要加$命令如下。
[rootredhat8 yy]# echo $aa
123本地变量的特点是只能影响当前shell不能影响子shell。
[rootredhat8 yy]# echo $aa
123
[rootredhat8 yy]#
[rootredhat8 yy]# echo $$
4716当前shell的PID是4716。下面打开一个子shell。
[rootredhat8 yy]# bash
[rootredhat8 yy]# echo $$
4947这个子shell 的PID是4947。
[rootredhat8 yy]# echo $aa[rootredhat8 yy]# 可以看到没有aa变量。
[rootredhat8 yy]# exit
exit
[rootredhat8 yy]# echo $$
4716
[rootredhat8 yy]# echo $aa
123再次退回到原来的bash又有了aa变量,情形如图所示。 定义变量除刚才显式的定义外还可以使用如下两种方法。 方法1把一个命令的结果赋值给一个变量这个变量要使用$()括起来或者用反引号“引起来。这里是反引号与波浪号是同--个键,不是单引号。 例如定义一个名称是ip的变量对应的值是ens160的IP命令如下。
[rootredhat8 yy]# ip$(ifconfig ens160 | awk /inet /{print $2})
[rootredhat8 yy]# echo $ip
192.168.184.100方法2通过read命令来获取变量。 read的用法如下。
read ‐p 提示信息 变量 当遇到read命令时系统会等待用户输入用户所输入的值会赋值给read后面的变量 命令如下。
[rootredhat8 yy]# read -p 请输入您的名字 aa
请输入您的名字tom
[rootredhat8 yy]# echo $aa
tom当执行read这条命令时系统会提示用户输人一些内容所输入的内容会赋值给aa变量。这里我们输入的是 tom所以打印aa变量时看到的值是tom。 这样的用法比较适合写需要和用户交互的脚本。
2.2 环境变量 定义环境变量的注意点和本地变量是一样的。在定义环境变量时前面加上export 即可,命令如下。
[rootredhat8 yy]# export bb123或者先定义为本地变量然后再通过export转变为环境变量命令如下。
[rootredhat8 yy]# bb123
[rootredhat8 yy]# export bb要想查看所有的环境变量可以执行env命令。 环境变量的特点是可以影响子shell这里强调的是子shell不能影响父shell。
[rootredhat8 yy]# echo $$
4716
[rootredhat8 yy]# echo $bb
123当前shell的PID是4716里面有一个环境变量 bb。
[rootredhat8 yy]# bash
[rootredhat8 yy]# echo $$
5126
[rootredhat8 yy]# echo $bb
123打开一个子shellPID为5126里面可以看到bb变量的值说明环境变量已经影响到子shell 了。
[rootredhat8 yy]# export bb456
[rootredhat8 yy]# exit
exit在子 shell中重新给bb赋值为456然后退回到父shell。
[rootredhat8 yy]# echo $$
4716
[rootredhat8 yy]# echo $bb
123可以看到在父shell 中bb的值仍然是123说明在子shell 中定义的变量不会影响到父 shell如图所示。 系统中默认已经存在很多个变量,如下所示。 1UID表示当前用户的uid。 2USER表示当前用户名。 3HOME表示当前用户的家目录 分别显示这些变量的值,命令如下。
[rootredhat8 yy]# echo $UID
0
[rootredhat8 yy]# echo $USER
root
[rootredhat8 yy]# echo $HOME
/root有一个很重要的环境变量PATH当我们执行命令时一定要指定这个命令的路径如果没有写路径则会到PATH变量所指定的路径中进行查询。先查看当前用户的PATH变量命令如下。\
[rootredhat8 yy]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/binPATH变量由多个目录组成每个目录之间用冒号“:”分隔我们把写好的脚本放在PATH变量指定的目录中之后运行此脚本时就不需要指定路径了。 查看tom用户的PATH变量命令如下。
[tomredhat8 yy]$ echo $PATH
/home/tom/.local/bin:/home/tom/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin这里展示了tom用户的PATH 变量如果tom写了一个脚本之后就可以把这个脚本放在自己家目录下的.local/bin或bin目录下~/.local/bin或~/bin)。如果这两个目录不存在创建出来即可。 以上定义的环境变量也只是在当前终端中生效关闭终端之后这个变量也就消失了。如果想让定义的变量永久生效可以写家目录的.bash_profile中。因为打开终端时首先会运家目录下的一个隐藏文件.bash_profile。
2.3 位置变量和预定义变量 运行脚本时有时后面是需要加上参数的。但是我们在写脚本时并不能预知后期在脚本后面跟上什么参数这时就能用到位置变量了位置变量如下。 $0表示脚本的名称。 $1表示第1个参数。 $2表示第2个参数。 ...... ${10}表示第10个参数。 ...... 这里$后面的数字如果不是个位数则要用{}括起来。 系统中还内置了一些预定义变量。 $#表示参数的个数。 $*表示所有的参数。 例1写一个带参数的脚本内容如下。
[rootredhat8 yy]# vim scl.yaml
[rootredhat8 yy]# cat scl.yaml
#/bin/bash
echo 这是我第一个脚本,脚本名称是 $0
echo 第 1 个参数是$1
echo 第 2 个参数是$2
echo 第 3 个参数是$3
echo 此脚本一共有 $# 个参数它们分别是$*给这个脚本加上可执行权限并加参数运行命令如下。
[rootredhat8 yy]# chmod x scl.yaml
[rootredhat8 yy]# ./scl.yaml tom bob mary
这是我第一个脚本,脚本名称是 ./scl.yaml
第 1 个参数是tom
第 2 个参数是bob
第 3 个参数是mary
此脚本一共有 3 个参数它们分别是tom bob mary运行这个脚本时共指定了3个参数tom、bob、mary它们分别赋值给了 $1、$2、$3。这里S#被自动赋值为3因为总共有3个参数所有的参数被赋值给$*。 例2运行如下命令。
[rootredhat8 yy]# set a b c d e f g h i j k查看此命令的第1个和第9个参数命令如下。
[rootredhat8 yy]# echo $1
a
[rootredhat8 yy]# echo $9
i第1个参数是a第9个参数是i。下面查看第10个参数命令如下。
[rootredhat8 yy]# echo $10
a0第9个参数是i那么第10个参数应该是j才对这里显示为a0为什么呢?因为这里先把$10当成了$10$1的值是a所以$10的值为a0。 所以在位置变量中数字超过10时要用{}括起来下面的命令才是正确的。
[rootredhat8 yy]# echo ${10}
j另外在引用变量时双引号和单引号是有区别的直接看一个例子。
[rootredhat8 yy]# xxtom
[rootredhat8 yy]# echo my name is $xx
my name is tom
[rootredhat8 yy]# echo my name is $xx
my name is $xx这里先定义一个变量xxtom如果变量在双引号中引用则会被解析成具体的值;如果变量出现在单引号中则不被解析。
3 返回值 执行某命令之后结果不是正确的就是错误的。命令正确执行了返回值为0如果没有正确执行则返回值为非零。返回值为非零不一定是语法错误执行结果如果有“否定”的 意思,返回值也为非零。例如, ping 192.168.26.3语法没有错误但是没有ping通,返回值 也为非零。 返回值记录在$?中且$?只记录刚刚执行过命令的返回值。因为$?的值会被新执行命令的返回值覆盖。 先执行一个 xxx命令命令如下。
[rootredhat8 yy]# xxx
bash: xxx: 未找到命令...
[rootredhat8 yy]# echo $?
127
[rootredhat8 yy]# echo $?
0先执行一个xxx命令这个命令是错误的命令$?记录的是刚刚执行过xxx命令的返回值。 所以查看$?的值是127是一个非零的值。再次查看$?的值时却变成了0因为这个$? 记录的不再是xxx命令的返回值而是它前面执行过的echo $?命令的返回值 逻辑上“否定”的意思也是可以体现出来的。例如下面的例子。
[rootredhat8 yy]# grep ^root /etc/passwd
root:x:0:0:root:/root:/bin/bash
[rootredhat8 yy]# echo $?
0这里在/etc/passwd过滤行开头为root的行结果找到了所以返回值为0。
[rootredhat8 yy]# grep ^rootxxx /etc/passwd
[rootredhat8 yy]# echo $?
1这里在/etc/passwd过滤行开头为rootxxx的行结果没有找到即使语法没有错误但是逻辑上有“否定”的意思,所以返回值为非零。
4数值运算 在写脚本时,有时我们经常要做一些数学运算。数学运算的符号如下。 1表示加。 2-表示减。 3*表示乘。 4/表示除。 5**表示次方。 进行数学运算的表达式有$(())、$[]、let等,命令如下。
[rootredhat8 yy]# echo $((23))
5
[rootredhat8 yy]# echo $((2*3))
6
[rootredhat8 yy]# echo $((2**3))
8
[rootredhat8 yy]# echo $[2**3]
8其中$(O)和$[]的用法是一样的如果不用这样的表达式看如下代码。
[rootredhat8 yy]# echo 2**3
2**3这里并不是计算的2的3次方而是直接把这4个字符打印出来了 let也可以用于数学运算命令如下。
[rootredhat8 yy]# let aa12
[rootredhat8 yy]# echo $aa
3这里aa的值就是为3。 下面来看不使用let的情况,命令如下。
[rootredhat8 yy]# aa12
[rootredhat8 yy]# echo $aa
12这里并没有把aa的值12当成数字而是当成了3个字符:“1”“”“2”所以结果显示的也是12。 可以实现定义aa为整数类型然后再做数学运算命令如下。
[rootredhat8 yy]# declare -i aa
[rootredhat8 yy]# aa12
[rootredhat8 yy]# echo $aa
3首先declare -i aa把aa定义为一个整数所以12等于3,然后赋值给aa.所以aa的值为3。 以上表达式不能求得小数如果要得到小数需要使用 bc 命令用法如下。
echo scaleN ; 算法 | bc这里N是一个数字,表示小数点后面保留几位。 计算2/3小数点后面保留3位命令如下。
[rootredhat8 yy]# echo scale3 ; 2/3 | bc
.666这里得到的结果是0.666整数部分的0没有显示。 计算7/6小数点后面保留3位命令如下。
[rootredhat8 yy]# echo scale3 ; 7/6 | bc
1.1665 比较、对比、判断 在写脚本时有时需要做一些比较例如两个数字谁大谁小两个字符串是否相同等。 做对比的表达式有[]、[[]]、test其中[]和 test这两种表达式的作用是相同的。[[]]和[]的不同在于,[[]]能识别通配符和正则表达式中的元字符[]却不能。 需要注意的是在比较时中括号和后续提及的比较符两边都要留有空格。
5.1数字的比较 数字的比较主要是比较两个数字谁大谁小或者是否相同。能用到的比较符有以下几种。 1-eq相等。 2-ne不相等。 3-gt大于。 4-ge大于等于。 5-lt小于。 6-le小于等于。 做完比较之后通过返回值来判断比较是否成立。 练习1判断1等于2命令如下。
[rootredhat8 yy]# [ 1 -eq 2 ]
[rootredhat8 yy]# echo $?
11是不能等于2的所以判断不成立返回值为非零。注意中括号和比较符两边的空格。 练习2判断1不等于2命令如下。
[rootredhat8 yy]# [ 1 -ne 2 ]
[rootredhat8 yy]# echo $?
01不等于2所以判断成立返回值为0。
5.2 字待串的比较 字符串的比较一般是比较两个字符串是否相同用得较多的比较符有以下两种。 1相同。 2!不相同。 做完比较之后通过返回值来判断比较是否成立。 练习1定义一个变量aatom然后做判断命令如下
[rootredhat8 yy]# aatom
[rootredhat8 yy]# [ $aa tom ]
[rootredhat8 yy]# echo $?
1变量aa的值和 tom完全相同所以判断成立返回值为0。 练习2在判断中匹配通配符命令如下。
[rootredhat8 yy]# aatom
[rootredhat8 yy]# [ $aa to? ]
[rootredhat8 yy]# echo $?
1这里定义aatom按照前面讲过的通配符to?匹配的应该是前两个字符为to第三个可以是任意字符所以 tom应该会被to?匹配到为什么返回值为非零呢? 原因在于在这一对中括号[]中是不能识别通配符的aa的值是t、o、m三个字符而等号后面是t、o、?这三个字符并没有把问号当成通配符所以判断不成立。 如果想识别通配符,那么就要用双中括号[[]]看下面的判断。
[rootredhat8 yy]# aatom
[rootredhat8 yy]# [[ $aa to? ]]
[rootredhat8 yy]# echo $?
1在[[]]中能识别通配符“?”所以这里判断成立返回值为0。 注意 1后面跟的是通配符如果想跟正则表达式比较符就不能使用了要换成~。 2一定要注意中括号和比较符两边的空格。 5.3 属性的判断 属性的判断用于判断一个文件是否具备某个属性常见的属性包括以下7种。 1-r具备读权限。 2-w具备写权限。 3-x具备可执行权限。 注意 以上三个属性不管是出现在u、g还是o上只要有就算判断成立。 -d一个目录。 -l一个软链接。 -f一个普通文件且要存在。 -e不管什么类型的文件只要存在就算判断成立。 判断/etc/hosts具备r权限命令如下。
[rootredhat8 yy]# ls -l /etc/hosts
-rw-r--r--. 1 root root 158 9月 10 2018 /etc/hosts
[rootredhat8 yy]# [ -r /etc/hosts ]
[rootredhat8 yy]# echo $?
0通过第一条命令可以看到/etc/hosts是具备r权限的判断/etc/hosts具备r权限自然成立,所以返回值为0。 判断/etc/hosts具备x权限命令如下。
[rootredhat8 yy]# [ -x /etc/hosts ]
[rootredhat8 yy]# echo $?
1这里判断/etc/hosts具备x权限但是/etc/hosts不管是u、g还是o都不具备x权限所以判断不成立返回值为非零。 如果做一个否定判断在前面加上叹号“!”即可。 判断/etc/hosts没有x权限命令如下。
[rootredhat8 yy]# [ ! -x /etc/hosts ]
[rootredhat8 yy]# echo $?
0这里判断/etc/hosts没有x权限判断是成立的所以返回值为0。 判断/etc是一个普通文件命令如下。
[rootredhat8 yy]# [ -f /etc/ ]
[rootredhat8 yy]# echo $?
1我们知道/etc是一个目录而不是一个文件所以这个判断是不成立的返回值为非零。 判断/etc不管是什么类型的只判断存在还是不存在命令如下。
[rootredhat8 yy]# [ -e /etc/ ]
[rootredhat8 yy]# echo $?
0这里/etc是存在的目录-e用于判断存在不存在不判断文件类型所以返回值为0。
5.4 使用连接符 前面讲的判断只是单个判断如果要同时做多个判断那么就需要使用连接符了。能用的连接符包括“”和“||”。 先看一下使用作为连接符用法如下。
判断1 判断2 只有两个判断都为真返回值为0)整体才为真只要有一个为假整体就为假。判断1如果为假判断2还有必要执行吗?没有因为整体已经确定为假了。判断1为真整体是真是假在于判断2所以判断2肯定是要执行的。
[rootredhat8 yy]# [ 1 -le 2 ] [ 2 -ge 3 ]
[rootredhat8 yy]# echo $?
1这里有两个判断,第一个判断是1小于等于2,这个判断成立第二个判断是2大于等于3,这个判断不成立。使用作为连接符需要两边的判断都成立整体才成立所以整个判断为假返回值为非零。
[rootredhat8 yy]# [ 1 -le 2 ] [ 2 -le 3 ]
[rootredhat8 yy]# echo $?
0这里有两个判断,第一个判断是1小于等于2,这个判断成立第二个判断是2小于等于3这个判断也成立。使用作为连接符需要两边的判断都成立整体才成立所以整个判断为真,返回值为0。 下面看使用||作为连接符用法如下。
判断1 || 判断2 两个判断只要有一个为真(返回值为0)整体就为真只有全都为假整体才为假。 判断1为真,整体已经确定为真所以判断2没有必要执行。 判断1为假,整体是真是假在于判断2所以判断2肯定是要执行的。
[rootredhat8 yy]# [ 1 -le 2 ] || [ 2 -ge 3 ]
[rootredhat8 yy]# echo $?
0这里有两个判断第一个判断是1小于等于2这个判断成立整体已经确定为真所以整个判断为真返回值为0。
[rootredhat8 yy]# [ 1 -ge 2 ] || [ 2 -ge 3 ]
[rootredhat8 yy]# echo $?
1这里有两个判断第一个判断是1大于等于2第二个判断是2大于等于3这两个判断都为假所以整个判断为假返回值为非零。
6 if判断语句 在脚本中执行某条命令需要满足一定的条件如果不满足就不能执行。此时我们就要用到 判断语句了。 先看if判断if判断的语法如下。
if 条件1 ; then
命令1
elif 条件2 ; then
命令2
else 命令3
fi 先判断if后面的判断是不是成立。 如果成立则执行命令1然后跳到f后面执行6后面的命令。 如果不成立则不执行命令1然后判断elif后面的条件2是不是成立。 如果成立则执行命令2然后跳到f后面执行f后面的命令。 如果不成立则不执行命令2进行下一轮的elif 判断以此类推。 如果所有if和elif都不成立则执行clse中的命令3。 写一个脚本/opt/sc1.sh要求只有root用户才能执行此脚本其他用户不能执行,命令如下。
[rootredhat8 opt]# cat /opt/sc1.sh
#/bin/bash
if [ $UID -ne 0 ]; thenecho只有root才能执行此脚本exit 1
fi
echo hello root
[rootredhat8 yy]# chmod x /opt/sc1.sh 脚本分析如下。 root的uid是0其他用户的uid不为0。第一个判断如果uid不等于0则打印警告信息“只有root才能执行此脚本”然后exit退出脚本。 如果这里不加 exit判断之后仍然会继续执行echo hello root命令这样判断就失去了意义。只有加了exit之后如果不是root则到此结束不要继续往下执行了。 如果是tom执行此脚本则判断成立打印完警告信息之后通过exit退出脚本。 如果是 root执行此脚本则判断不成立直接执行f后面的命令。
使用root用户执行此脚本的结果如下。
[rootredhat8 opt]# /opt/sc1.sh
hello root使用blab用户执行此脚本的结果如下。
[tomredhat8 opt]$ /opt/sc1.sh
echo只有root才能执行此脚本写一个脚本 lopt/sc2.sh运行脚本时后面必须跟一个参数参数是系统中的一个文件 如果这个文件不存在则显示该文件不存在如果存在则显示该文件的行数命令如下。
[rootredhat8 opt]# cat /opt/sc2.sh
#!/bin/bash
if [ $# -eq 0 ] ; thenecho 脚本后面必须跟一个参数exit 1
fi
if [ -f $1 ] ; thenwc -l $1
elseecho $1不存在
fi脚本分析如下。 $#表示参数的个数第一个判断中$#的值如果等于0则说明脚本后面没有跟任何参数打印“脚本后面必须跟一个参数”然后退出脚本。 如果后面跟了参数则第一个判断不成立然后进行下一个if判断。 第一个参数用$1来表示[ -f $1 ]用于判断所跟的参数是不是存在如果存在则执行wc -1 $1命令如果不存在则执行else 中的命令。 运行脚本效果如下。
[rootredhat8 opt]# /opt/sc2.sh
脚本后面必须跟一个参数这次运行没有跟任何参数则提示必须跟一个参数。
[rootredhat8 opt]# /opt/sc2.sh /etc/hostxxx
/etc/hostxxx不存在这里跟了一个不存在的文件/etc/hostsxxx脚本提示这个文件不存在。
[rootredhat8 opt]# /opt/sc2.sh /etc/hosts
2 /etc/hosts这次脚本后面跟了一个存在的文件/etc/hosts脚本会显示该文件的行数为2行。
7 for循环语句 有时我们需要做多次重复的操作例如创建100个用户创建一个用户需要两条命 令:useradd和 passwd。那么创建100个用户就要重复执行100次总共执行200条命令此时我们就可以利用for循环简化操作让系统自动帮我们重复运行即可。 for循环的语法如下。
for 变量 in 值‐1 值‐2 值‐3 值‐4 ; do
命令 $变量
done 这里首先把值-1赋值给变量执行do和done之间的命令所有命令执行完成之后再把值-2赋值给变量执行do和done之间的命令执行完所有命令之后再把值-3赋值给变量以此类推,直到把所有的值都赋值给变量。 看一个简单的例子如下所示。
[rootredhat8 opt]# for i in 1 2 3 4 ; dolet i$i10echo $idone
11
12
13
14这里for后面定义了一个变量i在in后面指定了4个值分别是1、2、3、4。在do和done之间定义了两个命令第一个是在变量i的原有值的基础上加上10然后打印i的值。 先把1赋值给i此时i的值为1执行do和 done之间的命令。i加上10之后,i的值变为了11然后打印i得到11第一次循环结束。 然后把2赋值给i此时i的值为2执行do和done之间的命令。i加上10之后i的值变为了12然后打印i,得到12第二次循环结束。
8 while 循环语句 while也可以循环while循环的语法如下。
while 判断 ; do
命令1
命令2
done 如果while后面的判断成立则执行do和 done之间的命令在最后一个命令执行完成之后,会回头再次判断一下while后面的判断是不是成立。如果不成立则跳出循环执行done后面的命令;如果成立则继续执行do和 done之间的命令就这样循环下去。 先看一个简单的例子写一个脚本/opt/sc3.sh命令如下。
[rootredhat8 opt]# vim /opt/sc3.sh
[rootredhat8 opt]# cat /opt/sc3.sh
#!/bin/bash
declare -i n1
while [ $n -le 4 ] ; doecho $nlet n$n1
done
[rootredhat8 opt]# chmod x /opt/sc3.sh 脚本分析如下。 这里先通过declare -i n1定义了一个整数类型的变量n初始值为1。然后进入while进行循环先判断$n的值是不是小于等于4如果成立则执行do和 done之间的命令。 一开始$n的值为1[ $n -le 4 ]这个判断成立则进人 do和done之间执行命令。首先打印Sn的值然后在此基础上给n 加上1所以n的值变为了2这样do和done之间的命令就执行完成了。然后再次到while后面进行判断此时$n的值为2依然满足小于等于4再次执行do 和 done之间的命令。 如此反复当$n的值最终能增加到4时打印然后加1此时n的值变为了5。当Sn的值变 为5之后while后面的判断就不再成立了此时会跳出 while循环。 用while也可以用于循环一个文件的内容用法如下。
while read aa ; do
命令
done file 这里read后面的变量aa是可以随意指定的整体的意思是首先读取file的第一行内容赋值给aa执行do和 done之间的命令。然后读取file的第二行内容赋值给aa执行do和done之间的命令直到读取到file的最后一行。 有时while需要一直循环下去死循环)语法如下。
while true ; do
命令
done
或
while ((1)) ; do
命令
done 下面写一个脚本来实时判断vsftpd是否启动如果没有启动则将vsftpd启动命令如下。
[rootredhat8 opt]# cat /opt/sc4.sh
#!/bin/bash
while : ; do systemctl is-active vsftpd /dev/nullif [ $? -ne 0 ]; thensystemcat start vsftpdfisleep 1
done
[rootredhat8 opt]# chmod x /opt/sc4.sh 这里写了一个 while循环可以一直循环下去循环中先判断vsftpd是否启动如果启动了则返回值为0如果没有启动则返回值为非零。 下面开始根据返回值来进行判断如果$?不等于0说明vsftpd没有启动则启动vsftpd服务。sleep 1的意思是暂停1秒这样就实现了每隔1秒来判断一次vsfilpd是否启动。 下面开始测试这个脚本先把脚本放在后台运行,命令如下。
[rootredhat8 opt]# /opt/sc4.sh
[1] 38619测试当前vsftpd 的状态命令如下。
[rootredhat8 opt]# systemctl is‐active vsftpd
active
关闭vsftpd服务之后再次检测vsftpd 的状态命令如下。
[rootredhat8 opt]# systemctl stop vsftpd
[rootredhat8 opt]# systemctl is‐active vsftpd
active
可以看到vsftpd 仍然是启动的说明我们的脚本生效了。