shell脚本

目录

前言

一、shell脚本简介

二、判断式

1.test命令

 2、判断符号[]

3、shell脚本的默认变量

三、条件判断式

 1、if..then

2、case ... esac

3、函数function功能

四、循环

1、不定循环

while do done

until do done

2、固定循环

总结


前言

    本篇介绍shell脚本,内容皆总结摘抄自《鸟哥的linux私房菜:基础学习篇》,仅作笔记。


一、shell脚本简介

    shell script即shell 脚本,其中shell是在命令行模式下与系统沟通的一个工具接口,script是脚本的意思。shell脚本就是利用shell的功能写一个程序,这个程序是使用纯文本文件,将一些shell的语法和命令写在里面,搭配正则表达式、管道命令和数据流重定向功能,以达到我们想要的处理目的。

    shell脚本可以一次执行多个命令,或者利用一些运算与逻辑判断来完成某种功能。虽然shell脚本是一个文本文件,但要编写它的内容还是需要具备一些bash命令的相关知识,部分bash命令前面的文章介绍过此处不再赘述。shell脚本的编写需要注意以下几点:

  • 命令是从上而下、从左而右地分析与执行。
  • 命令、选项与参数间的多个空格都会被忽略。
  • 空白行也会被忽略,且tab键所产生的空白同样视为空格,因此也会被忽略。
  • 如果一行的内容太多,可以使用\Enter来扩展至下一行。
  • #可作为注释,任何加在#后面的数据都被视为注释文字而被忽略。

    一个简单的仅输出hello world的shell脚本内容如下:

#!/bin/bash
# Description:
#       it is just a shell script for testing.
# History:
#       2021/07/14 charles test
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
export PATH
echo -e "hello world \a \n"
exit 0

    以上程序可以分为以下几种结构:

  1. 第一行#!/bin/bash声明这个脚本使用的shell名称。因为我们使用的是bash,因此必须要用#!/bin/bash来声明这个文件使用bash的语法。这样以#!开头的行被称为shebang行。当这个程序被执行时,它就能够加载bash的相关环境配置文件(一般是非登陆shell的./bashsrc)并且执行bash来使我们下面的命令能够执行。
  2. 程序内容说明。除了第一行的#!是用来声明shell的类型,其他的#都是用作注释。一般来说,编写shell脚本时都需要说明该脚本的:①内容与功能;②版本信息;③作者与联系方式;④文件创建日期;⑤历史记录等等。
  3. 主要环境变量的声明。程序执行前最好先将一些重要的环境变量设置好,这样程序在执行时就可以直接执行一些外部命令,而不用写绝对路径。
  4. 主要程序部分。这个就是为了达到某种目的或效果编写的程序代码。
  5. 程序返回值。之前的文章中介绍过#?变量保存了上一个命令的执行结果,且当执行结果为0是表示程序正常执行,否则表示执行报错。在shell脚本中我们也可以使用exit命令来让程序中断,并且返回一个值给系统。除了正常执行返回0外,我们还可以自定义错误信息来返回不同的值。

    shell脚本写好之后下面要做的就是执行了,执行方式包括直接命令执行和以bash程序执行。直接命令执行需要要执行的文件具有可读与可执行的权限(rx),包括以下几种:

  • 绝对路径,例如使用/var/tmp/test来执行命令;
  • 相对路径,假设工作目录在/var/tmp目录,则可以使用./test命令来执行;
  • 变量$PATH功能,将test放在$PATH变量指定的目录内。

    以上容易有疑问的是相对路径,当工作目录在shell脚本目录时仍需要使用相对路径”./“而不是直接执行,这是为了避免执行到其他的同名命令,与前面的文章介绍过命令查找顺序有关。以bash程序执行可以通过"sh test"或“bash test”执行,使用这种方式执行shell脚本权限只需要读权限(r)即可。

    除了以上提到的几种,脚本的执行还可以使用source命令来执行,并且与上面的执行方式是有差异的。不论是使用绝对路径/相对路径还是#PATH,亦或是使用bash来执行脚本,该脚本都会使用一个新的bash环境来执行脚本内的命令。也就是说使用这种方式是,其实脚本是在子进程的bash中执行的。在前面的文章中提到过,在子进程完成后,在子进程内的各项变量或操作将会结束而不会传回父进程中。例如我们编写一个新的shell.sh脚本,内容如下:

#!/bin/sh
# Program:
#       a son thread for testing.
# History:
#       2021/07/14 charles test
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
export PATH
read -p "Please input your name:" name
read -p "Please input your gender:" gender
echo -e "My name is ${name} and my gender is ${gender}"

    当我们使用sh方式来执行此脚本后,在父进程中试图获取变量name和gender失败。

     使用source命令则是直接在父进程中执行,因此执行完上述脚本后仍可以拿到变量name和gender。

二、判断式

1.test命令

    test命令可以说是专门用作条件判断的,使用ls /varrr;echo $?命令来判断某个文件是否存在的场景如果使用test命令就变得极其简单。test命令的主要几种功能以及选项参数的说明如下表:

选项参数说明
1.判断某文件名是否存在并且是否为某种类型
-e文件名是否存在
-f文件名是否存在且类型为文件file
-d文件名是否存在且类型为目录directory
-b文件名是否存在且类型为block device设备
-c文件名是否存在且类型为character device设备
-S文件名是否存在且类型为socket文件
-p文件名是否存在且类型为FIFO(pipe)文件
-L文件名是否存在且类型为链接文件
2.判断某文件名是否存在并且具有某种权限
-r文件名是否存在且具有可读权限
-w文件是否存在且且具有可写权限
-x文件是否存在且且具有可执行权限
-u文件是否存在且且具有SUID权限
-g文件是否存在且且具有SGID权限
-k文件是否存在且且具有Sticky bit权限
-s文件是否存在且为非空文件
3.两个文件之间的比较
-ntnewer than 判断file1是否比file2新,test file1 -nt file2
-otolder than 判断file1是否比file2旧
-ef判断file1与file2是否为同一个文件,可用在判断hard link的判定上,主要意义在于判定两个文件是否均指向同一个innode
4.关于两个整数之间的判定
-eqequal 两个数的值是否相等,test n1 -eq n2
-nqnot equal 两个数的值是否不等
-gtgreater than n1是否大于n2
-ltless than n1是否小于n2
-gegreater than or equal n1是否大于等于n2
-leless than or equal n1是否小于等于n2
5.判断字符串
test -z string判断字符串string是否为0?若string为空字符串,则为true
test -n string判断字符串是否为非0?若string为空字符串,则为false
test str1 == str2判断str1是否等于str2,若相等则返回true
test str1 != str2判断str1是否不等于str2,若相等则返回false
6.多重条件判定
-aand 两条件同时成立,例如test -r file -a -x file,则file同时具有r和x权限时,才返回true
-oor 两条件任何一个成立,例如test -r file -o -x file,则file具有r或x权限时,就会返回true
!反相状态,例如test ! -x file,当file不具有x权限时,返回true

    使用test命令以及前面介绍过的特殊符号来尝试写个shell脚本。首先让用户输入一个文件名,然后判断这个文件是否存在。若不存在则返回“Filename does not exist”信息,并中断程序;若存在,则判断它是个文件还是目录,并输出“Filename is regular file”或“Filename is directory”,然后输出执行者对这个文件或目录所拥有的权限并输出权限数据。

#!/bin/bash
#program:
#       a tested shell script for 'test' command's testing.
# History:
#       2021/07/15 charles test
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
export PATH
# input a file name
read -p "Please input a file name:" fileName
# judge the fileName valid
test -z ${fileName} && echo "Please input a non empty file name." && exit 0
# judge the fileName whether existed
test ! -e ${fileName} && echo "Filename does not exist." && exit 0
# judge the fileName is a file or a directory
test -f ${fileName} && fileType="file"
test -d ${fileName} && fileType="directory"
test -r ${fileName} && authority="r"
test -w ${fileName} && authority="${authority}w"
test -x ${fileName} && authority="${authority}x"
echo "The fileName is a ${fileType} and the permissions for you are: ${authority}."

    执行这段脚本,分别传入不存在的文件、存在的目录以及存在的文件作为参数,输出结果如下:

    可以看到是符合我们的预期的。笔者开始写的脚本输入合法的目录仍然会直接退出,最后发现还是对前面的文章提到过的“&&”和“||”的使用不太熟悉,因此建议尝试自己多练习几次,实在写不出来再看结果以加深印象。

 2、判断符号[]

    中括号[]也可以用来做条件判断,且用法与test命令类似。例如判断某个变量是否为空可以使用命令“[ -z ""${name} ]”:

    中括号在多个地方被使用,例如通配符和正则表达式等。因此在bash脚本中使用中括号作为判断式时,需要注意以下几点:

  • 中括号内的每个组件之间都需要用空格来分隔,组件与中括号[]也需要;
  • 在中括号内的变量,最好都以双引号括起来;
  • 中括号内的常数,最好都以单引号或双引号括起来。

3、shell脚本的默认变量

    许多命令后面可以跟选项或参数,shell脚本同样也可以。脚本针对参数已经设置了一些默认的变量名称,对应如下:

/path/scriptnames opt1 opt2 opt3 opt4
      $0           $1   $2   $3   $4

    执行的脚本文件名即$0变量,后面的参数按照顺序取递增的变量名称,例如“$1”,“$2”等。除了这些数字变量外,还有一些特殊的变量可以在脚本内使用来调用这些参数:

  • $#:代表脚本后接的参数的个数,不包括表示脚本文件名称的$0变量,例如上面的例子中$#的值为4;
  • $@:表示脚本后接的所有参数,每个变量是独立的,例如上面的例子$@可以表示为opt1 opt2 opt3 opt4;
  • $*:表示脚本后接的所有参数,可指定分隔符,默认为空格,例如上面的例子$*可以表示为opt1 opt2 opt3 opt4。

    利用这几个变量尝试写个脚本,执行脚本后屏幕打印信息的逻辑如下:

  1. 程序的文件名;
  2. 参数数量;
  3. 如果参数数量小于1个,则输出参数数量太少;
  4. 全部参数的值。

    脚本内容如下:

#!/bash/bin
# Program:
#       default parameters's test,like $0,$1,$#,$@,and so on
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/application/java/jdk1.8.0_301/bin:/usr/application/nodejs/node-v14.17.3-linux-x64/bin:/root/bin
export PATH
echo "The scriptname is           => $0"
echo "The parameter's number is   => $#"
[ "$#" -eq 0 ] && echo "The parameter's number is too little..." && exit 0
echo "The parameter is 

    执行脚本分别传入0个参数个多个参数,屏幕打印信息如下:

     shift命令可以将默认参数的值向前偏移,类似于数据结构队列中的出队pop操作。例如修改上面的脚本,在脚本最后加入以下内容:

shift
echo "The parameter is            => $@"
shift 2
echo "The parameter is            => $@"

    第一行shift就是将变量$1的值设置为变量$2的值,变量$2的值设置为变量$3的值,依次类推。另外,shift命令后还可以接数字,表示偏移量,shift 2表示偏移量为2个。执行脚本传入5个变量屏幕打印信息如下:


     下面介绍shell脚本常使用的条件判断式和循环,由于要介绍的几种语法与大多数高级程序语言中的语法类似,因此仅简单介绍语法,不再写脚本示例。

三、条件判断式

 1、if..then

     if...then是最常见的条件判断式,当符合某个条件判断的时候就执行某项任务。只有一个判断式要判断时,其使用格式如下:

if 条件判断式;then
    当条件判断式成立时,执行的命令
fi

    在同一个数据的判断中,如果该数据需要进行多种不同的判断时,可以使用以下格式:

if 条件判断式;then
    当条件判断式成立时可执行的命令
else
    当条件判断式不成立时可执行的命令
fi

    或者更复杂的情况需要使用以下格式:

if 条件判断式一;then
    当条件判断式一成立时可执行的命令
elif 条件判断式二;then
    当条件判断式二成立时可执行的命令
...
else
    当前面的条件判断式都不成立时所执行的命令
fi

2、case ... esac

    case...esac判断与java中的switch...case语句功能类似,根据变量值的不同执行不同的命令。使用格式如下:

case 变量 in
    ”变量内容1“)
        变量的值为变量内容1时要执行的命令
    ;;
    ”变量内容2“)
        变量的值为变量内容2时要执行的命令
    ;;
    ...
esac

3、函数function功能

    函数在脚本中可以封装一些命令从而达到一处定义多处调用的目的,极大地简化了程序代码。function的语法如下:

function 函数名(){
    程序段
}

    前面提到过shell脚本的执行方式是由上向下、由左而右,因此为了保证脚本中可以调用我们定义的函数,应该把函数定义在脚本的最前面。function也拥有内置变量,且它的内置变量与shell脚本很类似,函数名称使用变量$0表示,后续接的其他变量按照顺序分别使用变量$1、$2...表示。

四、循环

    循环,即不断地执行某个程序段落,知道用户设置的条件完成为止。根据某种条件判断式来判断是否完成的循环叫做不定循环;相对应的,固定要跑多少次的循环叫做固定循环。

1、不定循环

    不定循环包括while do done和until do done两种语法。

while do done

    while do done的使用语法如下:

while 条件
do                    <====循环开始
  循环执行的程序段落
done                  <====循环结束

    以上这种循环表示当条件成立时就进行循环,直到条件不成立结束循环。

until do done

    until do done的使用语法如下:

until 条件
do                <====循环开始
    循环执行的程序段落
done              <====循环结束

    这种结束循环的方式与while相反,表示当条件成立时就终止循环,否则就一直循环。

2、固定循环

    固定循环使用语法for...do...done,这种语法是在执行时就已经知道了要进行几次循环,语法如下:

for 变量名称 in 变量值1 变量值2 变量值3 变量值4 变量值5...
do                            <====循环开始
    循环执行的程序段落
done                          <====循环结束                   
    

    上面的多个变量值也可以使用包含了多个值的变量来代替。for循环还可以使用以下语法:

for (( 初始值; 限制值; 赋值运算 ))
do
    循环执行的程序段落
done

    初始值表示某个变量在循环当中的起始值,类似i=1;限制值表示当变量的值在这个限制值的范围内的时候继续执行循环,例如i<100,否则结束循环;赋值运算表示每做一次循环变量的递增或递减,例如i=i+1。

总结

  • shell脚本用在系统管理上是很好的一种工具,但用在处理大量数值运算上就不太行了。因为shell脚本的速度较慢,且使用的CPU资源较多,会造成主机资源的分配不良。
  • shell脚本的执行,至少需要有r的权限;若需要执行命令,则需要用于r和x的权限。
  • 脚本如果使用source命令来执行,则代表在父程序的bash内执行。
  • 可以使用“sh -x 脚本名称”来进行程序的debug。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值