Linux学习笔记3-1:SHELL脚本

一、Shell编程基础

Linux系统的Shell环境允许用户通过交互式命令实现系统管理,同时用户还可以通过编写脚本文件实现执行过程完全自动化且功能更强大的系统管理工作,所以,相对于需要用户不断干预的命令行交互方式,脚本有着无可替代的优势。

Shell脚本文件的第一行一般都是这个样子:

!/bin/sh     #告诉系统应该调用哪个shell脚本解释器

1、变量、数组、运算符与输入参数

Shell变量的数据类型有两种,分别是数值字符串,数值变量比较简单和普通C语言差不多,字符串数据需要加上单引号或双引号。使用单引号的时候,引号中间的内容全部被当做普通字符,包括转义字符在单引号里面也被当成普通字符。使用双引号的时候,其中可以有转义字符还可以有变量,适用于字符串里包含变量的场景。

num1=8
num2=$[1+5]
str="Hello, please give \'me\' $num1 apples!"
echo $str    #运行结果是:Hello,please give 'me' 8 apples!
Shell脚本的变量名的命名规则:
  • 首个字符必须为字母(a-z,A-Z)。
  • 中间不能有空格,可以使用下划线(_)。
  • 不能使用标点符号。
  • 不能使用bash里的关键字(可用help命令查看保留关键字)。

查看bash的保留关键字

定义变量时,变量名前面不加$符号,且变量名、等号和变量值之间不能有空格。使用变量的时候需要加$符号,使用变量时,变量名外面建议使用大括号,这样会让代码更清晰。

first_name="adkada"
echo $first_name
echo ${first_name}

除了自定义的变量,Shell脚本还可以使用系统的环境变量,所有环境变量名都是大写的,可通过命令printenv查询:

这里写图片描述

使用“#”运算符获取字符串的长度

string="shell"
echo ${#string}   #输出5

如果使用符号#对一个数值变量获取长度,得到的结果是该数值的位数,所以,从这一点看,shell脚本把数值变量也当成了一种字符串。

从定义的字符串变量中提取子字符串

string="there is the way"
echo ${string:1:4}   #输出here

用括号定义数组,数组元素用”空格”符号分割开,例如:数组名=(值1 值2 … 值n)

array_name = {value0  value1  value2}

还可以单独定义数组的各个元素

array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen

读取数组某个元素的内容:${数组名[下标]}

${array_name[0]}

Shell脚本对于变量的定义方式不像C语言有严格的数据类型标识,导致在需要变量做数值计算的时候,为了不产生混乱,需要一些特殊的标识处理,这个在后面描述。

使用@ 或 * 可以获取数组中的所有元素

${array_name[*]}
${array_name[@]}

获取数组的长度

# 取得数组元素的个数(和字符串的处理相似,都是使用"#"运算符)
length=${#array_name[@]}
length=${#array_name[*]}

# 取得数组单个元素的长度
lengthn=${#array_name[0]}
lengthn=${#array_name[1]}
lengthn=${#array_name[n]}

获取Shell脚本的输入参数

普通的Linux命令一般都会有输入参数实现命令操作的灵活控制,Shell脚本在执行的时候也支持用户输入参数,脚本内部通过 $n 获取脚本的文件名和输入参数。

echo "脚本的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";

除了获取输入参数,Shell脚本还支持一些特殊的变量

特殊变量含义
$#获取传递到脚本的参数个数
$*传递给脚本或函数的所有参数
$@传递给脚本或函数的所有参数,加上”“号时与$*有差异
$?上个命令或函数的退出状态。0表示没有错误,其他表明有错误
$$当前运行Shell脚本所在的进程ID
$!后台运行的最后一个进程的ID号

$* 和 $@ 都表示传递给函数或脚本的所有参数,对于有多个参数的情况:

  • 如果不加双引号”“,两种符号都一样,都是以”$1” “$2” … “$n”的形式输出所有参数。此时有多个字符串。
  • 如果加双引号”“:
    • ”$*” 会将所有的参数作为一个整体,以”$1 $2 … $n”的形式输出所有参数,此时多个参数合并成一个字符串
    • “$@” 继续保持各个参数分开,以”$1” “$2” … “$n” 的形式输出所有参数。

Shell脚本支持的运算符

Shell支持的运算符包括:算数运算符关系运算符(比较两个数字变量的大小)布尔运算符(逻辑运算)字符串运算符(比较字符串变量)文件测试运算符(测试某个变量或表达式是否为文件或目录)

算数运算符 用于完成加、减、乘、除的数值运算
#! /bin/sh
a=10
b=20

val=`expr $a + $b`   #1.和定义普通变量一样,在'='号的前后都不能有空格
                     #2.运算表达式必须使用反引号标识,不能单引号,否则和字符串就没法区分了
                     #3.运算表达式以命令expr开头,且expr与后面的变量之间必须有空格
                     #4.运算符前后都必须有空格
echo "a + b : $val"  #执行结果:a + b : 30

val=`expr $a - $b`
echo "a - b : $val"  #执行结果:a - b : -10

val=`expr $a \* $b`  #乘号'*'前边必须加反斜杠'\'才能实现乘法运算
echo "a * b : $val"

val=`expr $b / $a`   #除法运算
echo "b / a : $val"

val=`expr $b % $a`   #取模运算(求余数)
echo "b % a : $val"

if [ $a != $b ]      #'!='判断两边的变量是否不相等,不相等则整个表达式为真true,否则为假false
then
   echo "a 不等于 b"  
fi

a=$b                 #将变量b的值赋值给变量a

if [ $a == $b ]      #'=='判断两边的变量是否相等,相等则整个表达式为真true,否则为假false
then
   echo "a 等于 b"
fi
关系运算符:用于比较两个数字是否相等。只支持数字,不支持字符串,除非字符串的值是数字。

因为shell脚本将><理解为输入输出重定向,而不是大于和小于。所以shell脚本中对于数值大小关系的比较采用如下所示的关键字:

if [ $a -eq $b ]     #-eq检测a、b是否相等,相等返回 true
if [ $a -ne $b ]     #-ne检测a、b是否不相等,不相等返回 true
if [ $a -gt $b ]     #-gt检测a是否大于b,大于返回 true
if [ $a -lt $b ]     #-lt检测a是否小于b,小于返回 true
if [ $a -ge $b ]     #-ge检测a是否大于等于b,是返回 true
if [ $a -le $b ]     #-le检测a是否小于等于b,是返回 true
布尔运算符:相当于C语言中的逻辑运算符
逻辑运算符含义
&&逻辑与,也可以写成-a,如果用-a的话,下面的例子中只能用一层中括号
||逻辑或,也可以写成-o,如果用-o的话,下面的例子中只能用一层中括号
!逻辑非
#! /bin/sh
a=10
b=20

if [[ $a -lt 100 && $b -gt 100 ]] # 这里使用[]作为测试运算符
                                  # ‘[' 和 ']'与expression之间都必须有空格
                                  # 这里使用两层[]是为了保证异常情况,内层[]返回false,脚本能继续执行
then
   echo "返回 true"
else
   echo "返回 false"
fi
字符串运算符:用于检测两个字符串之间的内容、长度是否相等,以及字符串内容是否为空。
运算符含义举例
=检测两个字符串是否相等,相等返回 true[ $a = $b ] 返回 false
!=检测两个字符串是否相等,不相等返回 true[ $a != $b ] 返回 true
-z检测字符串长度是否为0,为0返回 true[ -z $a ] 返回 false
-n检测字符串长度是否为0,不为0返回 true[ -n $a ] 返回 true
str检测字符串是否为空,不为空返回 true[ $a ] 返回 true
文件测试运算符:用于检测文件的各种属性,例如:
[ -d /etc/fstab ]  # 判断/etc/fstab是否为一个目录
操作符说明举例
-d $file检测文件是否是目录,如果是,则返回 true[ -d $file ] 返回 false
-f $file检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true[ -f $file ] 返回 true
-r $file检测文件是否可读,如果是,则返回 true[ -r $file ] 返回 true
-w $file检测文件是否可写,如果是,则返回 true[ -w $file ] 返回 true
-x $file检测文件是否可执行,如果是,则返回 true[ -x $file ] 返回 true
-b $file检测文件是否是块设备文件,如果是,则返回 true[ -b $file ] 返回 false
-c $file检测文件是否是字符设备文件,如果是,则返回 true[ -c $file ] 返回 false
-g $file检测文件是否设置了 SGID 位,如果是,则返回 true[ -g $file ] 返回 false
-k $file检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true[ -k $file ] 返回 false
-p $file检测文件是否是有名管道,如果是,则返回 true[ -p $file ] 返回 false
-u $file检测文件是否设置了 SUID 位,如果是,则返回 true[ -u $file ] 返回 false
-s $file检测文件是否为空(文件大小是否大于0),不为空返回 true[ -s $file ] 返回 true
-e $file检测文件(包括目录)是否存在,如果是,则返回 true[ -e $file ] 返回 true

2、内部命令与程序流程控制

echo命令

echo命令基本上就是用于字符串输出,比较有意思的是它还可以执行一个系统命令,并输出执行结果。

#! /bin/sh
echo `ls`     #在shell脚本的工作目录下执行ls命令,并返回查询结果
echo `date`   #执行date命令,并返回当前的日期

printf 命令

printf命令从功能上看和echo基本一致,都是用于打印字符串信息。两者的区别在于:
printf命令完全模仿C语言中printf函数的风格。所以,使用printf可以格式化字符串,还可以制定字符串的宽度以及左右对齐方式。默认printf不会像 echo 自动添加换行符,我们可以手动添加 \n。

printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg 

test命令

其实测试语句有两种表达方式,其中有一种在前面介绍运算符的时候已经出现了。
第一种形式: test expression
第二种形式: [ expression ],‘[’ 和 ‘]’与expression之间都必须有空格。

read命令

脚本的流程控制

if else条件分支判断
if condition1
then
    command1
elif condition2 
then 
    command2
else
    commandN
fi
for 循环
for var in item1 item2 ... itemN
do
    command1
    command2
    ...
    commandN
done
while 语句
while condition
do
    command
done
while :   # 这种属于无限循环
do
    command
done
until 循环
until condition
do
    command
done
case条件分支匹配
echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum                  #从键盘读取用户分支的输入
case $aNum in
    1)  echo '你选择了 1'
    ;;                     #两层分号表示一个case分支结束
    2)  echo '你选择了 2'
    ;;
    3)  echo '你选择了 3'
    ;;
    4)  echo '你选择了 4'
    ;;
    *)  echo '你没有输入 1 到 4 之间的数字'
    ;;
esac                       #esac表示全部case分支结束
break命令:终止命令,即跳出后面的所有循环
#!/bin/bash
while :
do
    echo -n "输入 1 到 5 之间的数字:"
    read aNum
    case $aNum in
        1|2|3|4|5) echo "你输入的数字为 $aNum!"
        ;;
        *) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
            break
        ;;
    esac
done
continue命令:跳出当前的循环,外层循环不受影响

3、函数、输入输出重定向与文件包含

函数定义与函数参数

Shell函数的定义形式和C语言有点相似,不过没有严格的返回值类型和参数类型。
demoFun()
{
    echo "这是我的第一个 shell 函数!"
    echo "第一个参数为 $1 !"
    echo "第二个参数为 $2 !"
    echo "第十个参数为 $10 !"
    echo "第十一个参数为 $11 !"
    echo "参数总数有 $# 个!"
    echo "作为一个字符串输出所有参数 $* !"
}
echo "-----函数开始执行-----"
demoFun 1 2 3 4 5 6 7 8 9 10 11
echo "-----函数执行完毕-----"

在函数的的最后,可以显示调用return返回一个0~255之间的整数,否则,shell将以最后一条命令运行结果,作为返回值。

IO重定向

默认情况下,Shell命令的输入输出都是用户的标准终端(键盘和屏幕),这也体现了交互式的系统操作。更多的情况下,为了体现脚本语言的胶水作用以及自动化的处理过程,必须将脚本的输入和输出重定向到文件。

命令说明
command > file将输出重定向到 file文件,command的输出会覆盖原有文件file中的内容
command < file将输入重定向到 file文件
command >> file将输出以追加的方式重定向到 file文件
command1 < infile > outfile同时替换输入和输出,执行command1,从文件infile读取内容,然后将输出写入到outfile中
command > /dev/null如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null
n > file将文件描述符为 n 的文件重定向到 file文件,这里的n一般是:0 标准输入,1 标准输出,2 标准错误
n >> file将文件描述符为 n 的文件以追加的方式重定向到 file文件,这里的n一般是:0 标准输入,1 标准输出,2 标准错误
n >& m将输出文件 m 和 n 合并
n <& m将输入文件 m 和 n 合并
<< tag将开始标记 tag 和结束标记 tag 之间的内容作为输入

包含外部的脚本文件实现模块共享

Shell脚本可以通过“. filename”或“source filename”的方式包含一个外部的脚本文件。然后,就可以调用外部文件的函数和全局变量了。

第一个脚本文件:demo.sh
#!/bin/bash

demoFun()
{
    echo "这是我的第一个 shell 函数!"
    echo "第一个参数为 $1 !"
    echo "第二个参数为 $2 !"
    echo "第十个参数为 $10 !"
    echo "第十个参数为 ${10} !"
    echo "第十一个参数为 $11 !"
    echo "参数总数有 $# 个!"
    echo "作为一个字符串输出所有参数 $* !"
}
第二个脚本文件:hellow.sh
#!/bin/bash
source demo.sh   #或者这里可以写成“. demo.sh”

echo "-----函数开始执行-----"
demoFun 1 2 3 4 5 6 7 8 9 10 11
echo "-----函数执行完毕-----"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值