19 Star 187 Fork 90

baoke / Linux学完就忘系列

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
17.shell条件测试,逻辑判断,参数传递.md 9.59 KB
一键复制 编辑 原始数据 按行查看 历史

条件测试

判断某需求是否满足,需要由测试机制来实现;

如何编写测试表达式以实现所需的测试:
(1) 执行命令,并利用命令状态返回值来判断;
0:成功
1-255:失败

#判断是否有空白行
grep "^$" /etc/rc.d/init.d/functions &> /dev/null
#查看命令状态返回值
echo $?

#判断登录用户名为centos的用户
who | grep "^centos/>"
#查看命令状态返回值
echo $?

(2) 测试表达式
test EXPRESSION
[ EXPRESSION ]
[[ EXPRESSION ]]

注意:EXPRESSION两端必须有空白字符,否则为语法错误;

bash的测试类型:
数值测试
字符串测试
文件测试

数值测试:数值比较
-eq:是否等于; [ $num1 -eq $num2 ]
-ne:是否不等于;
-gt:是否大于;
-ge:是否大于等于;
-lt:是否小于;
-le:是否小于等于;

test 2 -eq 3
echo $?
test 2 -ne 3
echo $?

字符串测试:
==:是否等于;

:是否大于;
<:是否小于;
!=:是否不等于;
=~:左侧字符串是否能够被右侧的PATTERN所匹配;
-z "STRING": 判断指定的字符串是否为空;空则为真,不空则假;
-n "STRING": 判断指定的字符串是否不为空;不空为真,不空为假;

[ tom == Tom ]
echo $?  
[ tom == tom ]
echo $?

#判断是否为空
[[ -z "" ]]
echo $?
#判断是否为空
[[ -z "abc" ]]
echo $?

注意:变量做比较,万一某个变量的值为空就麻烦了;使用变量作比较记得给变量加双引号;

字符串比较,要使用[[ ]]

name=tom 
#匹配字符串中是否有o这个字符
[[ $name =~ o ]]
echo $?
name=jerry
[[ $name =~ o ]]
echo $?

文件测试
存在性测试:存在则为真,否则则为假;
-a和-e都用于表示文件存在性测试,一般使用-e
-a /PATH/FILE
-e /PATH/FILE

#查看文件是否存在
[ -e /etc/fstab ]
echo $?

存在性及类型测试
-b FILE:是否存在并且为块设备文件;
-c FILE:是否存在并且为字符设备文件;
-d FILE:是否存在并且为目录文件;
-f FILE:是否存在并且为普通文件;
-h FILE或-L FILE:是否存在并且为符号链接文件;
-p FILE:是否存在且为命名管道文件;
-S FILE:是否存在且为套接字文件;

#判断是否存在且是块设备
[ -b /dev/sda ]
echo $?
#查看文件类型
file /dev/sda
[ -b /dev/sdb ]
echo $?

文件权限测试:
-r FILE:是否存在并且对当前用户可读;
-w FILE:是否存在并且对当前用户可写; -x FILE:是否存在并且对当前用户可执行;

特殊权限测试: -u FILE:是否存在并且拥有suid权限;
-g FILE:是否存在并且拥有sgid权限;
-k FILE:是否存在并且用用stlcky权限;

#是否存在并且拥有suid权限
[ -u /usr/bin/passwd ]
echo $?

文件是否有内容:
-s FILE:是否有内容;

touch /tmp/hello
#新建的文件肯定没有内容
[ -s /tmp/hello ]
echo $?

文件时间戳测试:
-N FILE:文件自从上一次读操作后是否被修改过;

从属关系测试:
-O FILE:当前用户是否为文件的属主;
-G FILE:当前用户是否属于文件的属组;

双目测试:
FILE1 -ef FILE2:测试FILE1与FILE2是否为指向同一个文件系统的相同inode的硬链接;
FILE1 -nt FILE2:FILE1更新时间是否新于FILE2;
FILE1 -ot FILE2:FILE1更新时间是否旧于FILE2;

组合测试条件:
逻辑运算:
第一种方式:
COMMAND1 && COMMAND2
COMMAND1 || COMMAND2
!COMMAND

测试文件是否为属主,并且可读
[ -O FILE ] && [ -r FILE ]

[ -O /etc/fstab ] && [ -r /etc/fstab ]
echo $?

第二种方式:
[ EXPRESSION1 -a EXPRESSION2 ]
[ EXPRESSION1 -o EXPRESSION2 ]
[ ! EXPRESSION1 ]

[ -O /etc/fstab -a -x /etc/fstab ]
echo $?

练习:将当前主机名称保存至hostName变量中;
主机名如果为空,或者为localhost.localdomain,则将其设置为www.abc.com;

hostName=$(hostname)
[ -z "$hostName" -o "$hostName" == "localhost.localdomain" ] && hostname www.abc.com
hostname

脚本的状态返回值:
默认是脚本中执行的最后一条命令的状态返回值;
自定义状态退出状态码;
exit [n]:n为自己指定的状态码; 0:成功,1-255:失败;
注意:shell进程遇到exit时,即会终止,因此,整个脚本执行即为结束;

id user1 &> /dev/null && exit 0 || useradd user1

向脚本传递参数

#像/etc,/var传递给命令的参数,称之为位置参数
ls /etc /var

位置参数变量
myscript.sh argu1 argu2
引用方式:
$1,$2,....,${10},${11},...

给shell脚本传递参数
以下使用vim编辑器编写sum.sh文件如下:

#!/bin/bash
echo $[$1+$2]

执行以上脚本

bash sum.sh 10 20

轮替:
shift [n]:位置参数轮替;
shift.sh文件创建

#/bin/bash

echo "First pos args:$1"
#踢掉了第一个参数
shift

echo "First pos args:$1"

执行以上脚本

bash shift.sh one two

修改shift.sh文件

#/bin/bash

echo "First and second pos args:$1,$2"
#踢掉前两个参数
shift 2

echo "Third pos args:$1"

执行以上脚本

bash shift.sh one two three

练习:写一个脚本,通过命令传递两个文本文件路径给脚本,计算其空白行数之和;
lines.sh文件:

#!/bin/bash

linecount1=$(grep "^$" $1 | wc -l)

linecount2=$(grep "^$" $2 | wc -l)

echo "total black lines:$[$linecount1+$linecount2]"

执行以上脚本

bash lines.sh /etc/fstab /etc/rc.d/init.d/functions

特殊变量

$0:脚本文件路径本身;
$#:脚本参数的个数;
$*:所有参数;("hello" "hi" "toyou")
$@:所有参数;("hello hi toyou")

pos.sh文件如下:

#!/bin/bash

echo "脚本文件本身:$0"
echo "只取脚本文件名:$(basename $0)"

echo $1,$2

echo "脚本参数个数:$#"

echo $*
echo $@

执行以上脚本:

chmod +x pos.sh
./pos.sh hello hi toyou

修改之前lines.sh文件如下:

#!/bin/bash

[ $# -lt 2 ] && echo "至少需要两个参数" && exit 1

linecount1=$(grep "^$" $1 | wc -l)

linecount2=$(grep "^$" $2 | wc -l)

echo "total black lines:$[$linecount1+$linecount2]"

执行以上脚本:

chmod +x lines.sh
./lines.sh /etc/fstab

选择执行:

单分支语句:
if 测试条件; then
代码分支
fi

双分支的if语句:
if 测试条件;then
条件为真时执行分支
else
条件为假时执行的分支
fi

示例:通过参数传递一个用户名给脚本,此用户不存在时,则添加之;
创建useradd.sh文件:

#!/bin/bash

if [ $# -lt 1 ];then
    echo "请输入需要创建的用户名"
    exit 2
fi


if ! grep "^$1\>" /etc/passwd &> /dev/null; then
    useradd $1
    echo $1 | passwd --sdtin $1 &> /dev/null
    echo "Add user $1 finished."
else
    echo "用户已经存在!"
fi
~         

执行以上脚本

chmod +x useradd.sh
./useradd.sh zhangsan
echo $?

用户交互:通过键盘输入数据,从而完成变量赋值操作;

read [option]... [name]...
-p 'PROMPT'
-t TIMEOUT

#read是一个内嵌命令,它也有外部命令的实现
type read

#read后面的name是个变量,会等待接收用户键盘输入内容赋值给name变量   
read name
#输出变量信息  
echo $name

#使用-p代表PROMPT提示信息
read -p "请输入用户名:" name 
echo $name

#-t 5代表5秒钟不操作,则自动退出输入
read -t 5  -p "请输入用户名:" name 

示例

#!/bin/bash

read -p "请输入用户名:" name

[ -z "$name" ] && echo "请输入用户名!" && exit 2

read -p "请输入密码(默认为123456):" pwd 

[ -z "$pwd" ] && pwd="123456"

if id $name &> /dev/null;then
   echo "$name 已经存在!"
else
   useradd $name
   echo $pwd | passwd --stdin $name
   echo "Add User $name finished."
fi

检测脚本中的语法错误

bash -n /path/to/some_script

调试执行

bash -x /path/to/some_script
例如下面的练习1使用调试执行

练习

1、通过命令行参数给定两个数字,输出其中较大的数值;

#!/bin/bash

declare -i max

if [ $# -lt 2 ]; then
   echo "至少要两个参数!"
fi

if [ $1 -gt $2 ];then
   max=$1
else
   max=$2
fi

echo "max number:$max."
#调试执行
bash -x big.sh 5 10

2、通过命令行参数给定一个用户名,判断其ID号是偶数还是奇数;

3、通过命令行参数给定两个文本文件名,如果某文件不存在,则结束脚本执行; 都存在时返回每个文件的行数,并说明其中行数较多的文件;

4、写一个脚本,完成如下功能:
(1) 列出当前系统识别到的所有磁盘设备;
(2) 如磁盘数量为1,则显示其空间使用信息;
否则,则显示最后一个磁盘上的空间使用信息;

#!/bin/bash

disks=$(fdisk -l /dev/[sh]d[a-z] | grep -o "磁盘 /dev/[hs]d[a-z]" | wc -l)

if [ $disks -eq 1 ];then
   fdisk -l /dev/[hs]da
else
   fdisk -l /dev/[sh]d[a-z] | grep -o "磁盘 /dev/[hs]d[a-z]" | tail -1 | cut -d' ' -f2
fi

5、接收用户输入磁盘名称,获取磁盘名称的信息

#!/bin/bash

read -p  "请输入磁盘名称:" diskfile

[ -z $diskfile ] && echo "必须输入磁盘名称!" && exit 2

if  fdisk -l | grep "磁盘 $diskfile" &> /dev/null;then
     fdisk -l $diskfile
else
   echo "错误的磁盘名称"
   exit 2
fi
Shell
1
https://gitee.com/abcd1234567_1/linux.git
git@gitee.com:abcd1234567_1/linux.git
abcd1234567_1
linux
Linux学完就忘系列
master

搜索帮助