linux整理-19-Shell的基本语法(变量,运算符,流程控制,数组,函数)

目录:

1、变量
    1.1、系统变量
    1.2、自定义变量
        1、语法
        2、示例
        3、变量高级用法
        4、反引号赋值
        5、变量有用技巧
    1.3、特殊变量
2、运算符
    2.1、算数运算符
        1、用expr
        2、用(())
        3、用$[]
        4、用let
        5、注意
    2.2、关系运算符
    2.3、布尔运算符
    2.4、字符串运算符
    2.5、文件运算符
3、流程控制
    3.1、if
    3.2、while
    3.3、case
    3.4、for
    3.5、until
4、数组
5、函数使用
6、函数参数
7、跨脚本调用函数

1、变量

1.1、系统变量

Linux Shell中的变量分为“系统变量”和“用户自定义变量
系统变量可以通过set命令查看,用户环境变量可以通过env查看
linux整理-19-Shell的基本语法(变量,运算符,流程控制,数组,函数)_第1张图片
常用系统变量:$PWD $SHELL $USER $HOME
linux整理-19-Shell的基本语法(变量,运算符,流程控制,数组,函数)_第2张图片
那自定义变量呢。?

1.2、自定义变量

1、语法

变量=值 (例如STR=abc)
等号两侧不能有空格
变量名称一般习惯为大写

使用变量: $STR
在这里插入图片描述

2、示例

linux整理-19-Shell的基本语法(变量,运算符,流程控制,数组,函数)_第3张图片
解释:

命令:ABC=huang bo,定义变量时中间带有空格,那么一定要带引号,不然不能定义
命令:ABC='huang bo',带了单引号则原样输出。表示引号中间的值是整体字符串
命令:ABC="huang bo",带了双引号,表是字符串中运行出现引用变量和转移字符等

在引号当中要引用变量的时候,单引号和双引号就有区别啦:
命令:

echo 'xu zheng $ABC' 和 echo "xu zheng $ABC"

请看区别:
如果是单引号,则引号当中的任何东西都当做字符串,即特殊字符会被脱意
如果是双引号,那么$ABC能打印出变量的值

单引号和双引号总结:

单引号:

1、单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的
2、单引号字串中不能出现单引号(对单引号使用转义符后也不行)

双引号:

1、双引号里可以有变量
2、双引号里可以出现转义字符

那假如命令是这样的:echo “xu zheng $ABCabc”,请问还能不能打印出变量ABC的值呢?
请看结果:
在这里插入图片描述
解决方法是:把变量名用大括号包起来

3、变量高级用法

撤销变量:unset ABC
声明静态变量:readonly ABC= ‘abc’ 特点是这种变量是只读的,不能unset

请先看一个例子,我现在写两个脚本,在a.sh中调用b.sh执行,那我们想知道a脚本能不能获取到b脚本的变量,b脚本能不能获取到a脚本的变量?
a.sh:

[root@hadoop02 bin]# vi a.sh
#!/bin/bash
A="A in a.sh"
echo $A
echo $B
/root/bin/b.sh

b.sh

[root@hadoop02 bin]# vi b.sh
#!/bin/bash
B="B in b.sh"
echo $A
echo $B

执行a.shz之后的结果:
在这里插入图片描述
在a.sh中只打印出了变量A的值,这个好理解,因为shell是顺序解析执行的,在打印变量B的时候,就算它能获取到b.sh当中的变量,它也还没执行,所以,肯定获取不到

那再看b.sh打印出来的结果:可以发现虽然a.sh当中的语句执行完了再调用b.sh来执行,但是b.sh脚本依然也没法获取到a.sh的变量

那怎么解决?
使用export关键字
export A=“A in a.sh”
意味着把变量提升为当前shell进程中的全局环境变量,可供其他子shell程序使用,
A变量就成了a.sh脚本所在bash进程的全局变量,该进程的所有子进程都能访问到变量A

另外一种使用方式
如果在a.sh脚本中用如下方式调用b.sh:

. /root/bin/b.sh    ## 注意:重点关注最前面那个“.”号

或者

source /root/bin/b.sh 

用上述两种方式意味着
b.sh就在a.sh所在的bash进程空间中运行

总结
1、a.sh中直接调用b.sh,会让b.sh在A所在的bash进程的“子进程”空间中执行
2、而子进程空间只能访问父进程中用export定义的变量
3、一个shell进程无法将自己定义的变量提升到父进程空间中去
4、source或者“.”号执行脚本时,会让脚本在调用者所在的shell进程空间中执行

4、反引号赋值

a=’ls -l /root/bin ##反引号,运行里面的命令,并把结果返回给变量a
另外一种写法:
a=$(ls -l /root/bin)

5、变量有用技巧
形式 说明
${var} 变量本来的值
${var:-word} 如果变量 var 为空或已被删除(unset),那么返回 word,但不改变 var 的值
${var:+word} 如果变量 var 被定义,那么返回word,但不改变 var 的值
${var:=word} 如果变量 var 为空或已被删除(unset),那么返回 word,并将 var 的值设置为 word
${var:?message} 如果变量 var 为空或已被删除(unset),那么将消息 message 送到标准错误输出,可以用来检测变量 var 是否可以被正常赋值。若此替换出现在Shell脚本中,那么脚本将停止运行

1.3、特殊变量

先来看看各个常用的特殊变量的概念:

$? 表示上一个命令退出的状态码
$$ 表示当前进程编号
$0 表示当前脚本名称
$n 表示n位置的输入参数(n代表数字,n>=1)
$# 表示参数的个数,常用于循环
∗ 和 *和 @ 都表示参数列表

示例:

[root@hadoop02 bin]# vi d.sh
#!/bin/bash
echo "test var"
echo $$
echo $0
echo $1
echo $2
echo $#
echo $*
echo $@
echo $?	

linux整理-19-Shell的基本语法(变量,运算符,流程控制,数组,函数)_第4张图片

注:$ *与$@区别
$* 和 $@ 都表示传递给函数或脚本的所有参数

不被双引号" "包含时  ====   $* 和 $@ 都以$1  $2  … $n 的形式组成参数列表

当它们被双引号" "包含时  ==== 
"$*" 会将所有的参数作为一个整体,以"$1 $2 … $n"的形式组成一个整串;
"$@" 会将各个参数分开,以"$1" "$2" … "$n" 的形式组成一个参数列表

区别示例:

[root@hadoop02 bin]# vi e.sh 
#!/bin/bash
echo $*
echo $@
echo "$*"
echo "$@"
echo --------------------
for a in $*
do echo $a
done
echo --------------------
for b in $@
do echo $b
done
echo --------------------
for a in "$*"
do echo $a
done
echo --------------------
for b in "$@"
do echo $b
done	

linux整理-19-Shell的基本语法(变量,运算符,流程控制,数组,函数)_第5张图片

2、运算符

2.1、算数运算符

1、用expr

格式 expr m + n 注意expr运算符间要有空格
例如计算(2+3)×4 的值

1、分步计算
	S=`expr 2 + 3`
	expr $S \* 4       ##   *号需要转义
2、一步完成计算
	expr `expr 2 + 3 ` \* 4
	    echo `expr \`expr 2 + 3\` \* 4`

[root@hadoop02 bin]# vi f.sh

#!/bin/bash
S=`expr 2 + 3`
expr $S \* 4

结果:
linux整理-19-Shell的基本语法(变量,运算符,流程控制,数组,函数)_第6张图片

取余:expr 4 % 3
在这里插入图片描述

用expr还可以计算字符串的长度,子字符串出现的位置,截取字符串等等

[hadoop@hadoop04 data]$ NAME='huangbohuanglei'  ## 定义
[hadoop@hadoop04 data]$ expr length $NAME       ## 求长度
[hadoop@hadoop04 data]$ expr index $NAME huang  ## 求子字符串首次出现的位置
[hadoop@hadoop04 data]$ expr substr $NAME 6 2    ## 从6开始,截取2两个字符

linux整理-19-Shell的基本语法(变量,运算符,流程控制,数组,函数)_第7张图片
详情请翻阅:expr --help

2、用(())
((1+2))
(((2+3)*4))
count=1
((count++))
((++count))
echo $count

但是要想取到运算结果,需要用$引用
a=$((1+2))
3、用$[]
SS=$[2+3]
echo $SS
SS=$[2*3]
echo $SS
echo $[(2 + 3)*3]	
4、用let
first=1
second=2
let third=first+second
echo ${third}
5、注意:以上命令都只对整形数值有效,不适用于浮点数

linux整理-19-Shell的基本语法(变量,运算符,流程控制,数组,函数)_第8张图片
如果有浮点数参与运算,可以将echo与bc命令结合起来使用,代码如下:
在这里插入图片描述
且看bc的一些强大作用:

echo "1.212*3" | bc         ## 简单浮点运算
echo "scale=2;3/8" | bc      ##将输出结果设置为2位
echo "obase=2;127" | bc     ##输出运算结果的二进制
echo "obase=10;ibase=2;101111111" | bc     ##将二进制转换成十进制
echo "10^10" | bc          ##求幂指数
echo "sqrt(100)" | bc        ##开平方

除了用bc做尽职转换以外,还可以这样做:
echo $((base#number)) 表示把任意base进制的数number转换成十进制
例子:

echo $((8#377))   返回255
echo $((025))		返回21 , 八进制
echo $((0xA4))    返回164 , 十六进制

使用bc还可以用来比较浮点数的大小:

[root@hadoop02 bin]# echo "1.2 < 2" |bc
1
[root@hadoop02 bin]# echo "1.2 > 2" |bc
0
[root@hadoop02 bin]# echo "1.2 == 2.2" |bc
0
[root@hadoop02 bin]# echo "1.2 != 2.2" |bc
1

看出规律了嘛?运算如果为真返回 1,否则返回 0,写一个例子

[root@hadoop02 bin]# [ $(echo "2.2 > 2" |bc) -eq 1 ] && echo yes || echo no
yes
[root@hadoop02 bin]# [ $(echo "2.2 < 2" |bc) -eq 1 ] && echo yes || echo no
no

2.2、关系运算符

下面给出一张关系运算符的列表:

运算符 等同运算符 说明
-eq = 检测两个数是否相等,相等返回true
-ne != 检测两个数是否相等,不相等返回true
-ge >= 检测左边的数是否大等于右边的,如果是,则返回true
-gt > 检测左边的数是否大于右边的,如果是,则返回true
-le <= 检测左边的数是否小于等于右边的,如果是,则返回true
-lt < 检测左边的数是否小于右边的,如果是,则返回true

2.3、布尔运算符

运算符 等同运算符 说明
! ! 非运算,表达式为 true 则返回false,否则返回true
-a && 与运算,两个表达式都为true 才返回true
-o ll 或运算,有一个表达式为true 则返回true

2.4、字符串运算符

运算符 说明
= 检测两个字符串是否相等,相等返回true
!= 检测两个字符串是否相等,不相等返回true
-z 检测字符串长度是否为0,为0返回true
-n 检测字符串长度是否为0,不为0返回true
str 检测字符串是否为空,不为空返回true

2.5、文件运算符

运算符 说明
-d 检测文件是否是目录,如果是,则返回true
-f 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true
-e 检测文件(包括目录)是否存在,如果是,则返回true
-s 检测文件是否为空(文件大小是否大于0),不为空返回true
-r 检测文件是否可读,如果是,则返回true
-w 检测文件是否可写,如果是,则返回true
-x 检测文件是否可执行,如果是,则返回true
-b 检测文件是否是块设备文件,如果是,则返回true
-c 检测文件是否是字符设备文件,如果是,则返回true

3、流程控制

3.1、if

语法格式:

if [ condition ]
then 
    statements 
[elif [ condition ]
    then statements. ..] 
[else 
    statements ] 
fi

示例程序:
[root@hadoop02 bin]# vi g.sh
#!/bin/bash
##read a value for NAME from stdin
read -p “please input your name:” NAME
##printf ‘%s\n’ $NAME
if [ $NAME = root ]
then
echo “hello ${NAME}, welcome !”
elif [ $NAME = hadoop ]
then
echo “hello ${NAME}, welcome !”
else
echo “I don’t know you !”
fi
linux整理-19-Shell的基本语法(变量,运算符,流程控制,数组,函数)_第9张图片

规则解释:
[ condition ] (注:condition前后要有空格)
#非空返回true,可使用$?验证(0为true,>1为false)
[ hadoop ]
#空返回false
[ ]
linux整理-19-Shell的基本语法(变量,运算符,流程控制,数组,函数)_第10张图片
注意[ ]内部的=周边的空格

短路运算符(理解为三元运算符)
[ condition ] && echo OK || echo notok
条件满足,执行&&后面的语句;条件不满足,执行||后面的语句
在这里插入图片描述
条件判断组合
条件判断组合有两种使用方式:
[] 和 [[]]
注意它们的区别:

[[ ]] 中逻辑组合可以使用 &&  || 符号
[] 里面逻辑组合可以用  -a   -o

linux整理-19-Shell的基本语法(变量,运算符,流程控制,数组,函数)_第11张图片

常用判断运算符:
1、字符串比较

= 判断相等
!= 判断不相等
-z 字符串长度是为0返回true
-n 字符串长度是不为0返回true

linux整理-19-Shell的基本语法(变量,运算符,流程控制,数组,函数)_第12张图片
2、整数比较

-lt 小于  less than 
-le 小于等于
-eq 等于
-gt 大于 great than
-ge 大于等于
-ne 不等于

.

[root@hadoop02 bin]# if [ 2 -lt 3 ]; then echo ok; else echo notok;fi  

在这里插入图片描述

3、文件判断

-d 是否为目录
		if [ -d /bin ]; then echo ok; else echo notok;fi
-f 是否为文件
		if [ -f /bin/ls ]; then echo ok; else echo notok;fi
-e 是否存在
		if [ -e /bin/ls ]; then echo ok; else echo notok;fi

3.2、while

语法格式:

# 实例一
while expression
do
   command
   ……
done	

# 实例二
i=1
while ((i<=3))
do
  echo $i
  let i++
done	

# 实例三
#!/bin/bash
i=1
while [ $i -le 3 ]
do
  echo $i
  let i++
done

命令执行完毕,控制返回循环顶部,从头开始直至测试条件为假
换种方式:循环体会一直执行,直到条件表达式expression为false
注意:上述let i++ 可以写成 i= ( ( (( ((i+1))或者i=$((i+1))

3.3、case

Case语法(通过下面这个例子展示):

case $1 in
start)
	echo "starting"
	;;
stop)
	echo "stoping"
	;;
*)
	echo "Usage: {start|stop}"
esac

3.4、for

语法格式:

for 变量 in 列表
do
command
……
done

列表是一组值(数字、字符串等)组成的序列,每个值通过空格分隔。每循环一次,就将列表中的下一个值赋给变量

三种方式
方式一
for N in 1 2 3; do echo $N; done
在这里插入图片描述

方式二
for N in {1…3}; do echo $N; done

在这里插入图片描述
方式三
for ((i=0; i<=2; i++)); do echo “welcome $i times”; done

在这里插入图片描述

3.5、until

语法结构:

until expression
do
   command
   ……
done

expression一般为条件表达式,如果返回值为 false,则继续执行循环体内的语句,否则跳出循环。
换种方式说:循环体会一直执行,直到条件表达式expression为true

示例:

#!/bin/bash
## vi util.sh
a=0
until [ ! $a -lt 3 ]
do
   echo $a
   a=`expr $a + 1`
done

在这里插入图片描述

4、数组

在Shell中,用括号来表示数组,数组元素用“空格”符号分割开。定义数组的一般形式为:

array_name=(value1 ... valuen)

例子:mingxing=(huangbo xuzheng wangbaoqiang)
也可以单独定义:mingxing[3]=liujialing
读取数组元素的格式是:${array_name[index]}
linux整理-19-Shell的基本语法(变量,运算符,流程控制,数组,函数)_第13张图片

获取数组下标:
[linux@linux ~]$ echo ${!mingxing[@]}
在这里插入图片描述

输出数组的所有元素:
[linux@linux ~]$ echo echo $ {mingxing[*]}
[linux@linux ~]$ echo echo ${mingxing[@]}
在这里插入图片描述

获取数组的长度:
[linux@linux ~]$ echo $ {#mingxing[*]}
[linux@linux ~]$ echo ${#mingxing[@]}
在这里插入图片描述

数组对接:
[linux@linux ~]$ mingxing+=(liuyifei liuyufeng)
在这里插入图片描述

删除数组元素,但是会保留数组对应位置,就是该值的下标依然会保留,会空着,之后,还可以填充其他的值进来。
删除第一个元素: [linux@linux ~]$ unset mingxing[0]
linux整理-19-Shell的基本语法(变量,运算符,流程控制,数组,函数)_第14张图片
遍历数组:

#!/bin/bash
IP=(192.168.1.1 192.168.1.2 192.168.1.3)
# 第一种方式
for ((i=0;i<${#IP[*]};i++))
do
	echo ${IP[$i]}
done

#第二种方式
for ip in ${IP[*]}
do
    echo $ip
done

效果:
在这里插入图片描述

数组的分片:
${arr[@]:number1:number2}
这里number1从下标number1开始取值,number2往后取几个元素,即取到的新的数组的长度
在这里插入图片描述

5、函数使用

函数的语法使用示例:

[root@hadoop02 bin]# vi i.sh 
#!/bin/sh
hello(){
     echo "`date +%Y-%m-%d`"
     # return 2
}
hello
echo “huangbo” 
# echo $?
A="mazhonghua"
echo $A	

在这里插入图片描述
函数的调用方式就是直接写函数名就OK了

注意:

1、必须在调用函数地方之前,先声明函数,shell脚本是逐行运行。不会像其它语言一样先预编译
2、函数返回值,只能通过$? 系统变量获得,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255)

脚本调试
使用**-x选项跟踪脚本调试shell脚本**,能打印出所执行的每一行命令以及当前状态
sh -x i.sh
或者在代码中加入:set -x
linux整理-19-Shell的基本语法(变量,运算符,流程控制,数组,函数)_第15张图片

6、函数参数

[root@hadoop02 bin]# vi funcWithParam.sh
#!/bin/bash
# filename=funcWithParam
funcWithParam(){
    echo "第一个参数为 $1 !"
    echo "第二个参数为 $2 !"
    echo "第十个参数为 $10 !"
    echo "第十个参数为 ${10} !"
    echo "第十一个参数为 ${11} !"
    echo "参数总数有 $# 个!"
    echo "作为一个字符串输出所有参数 $* !"
}
funcWithParam 1 2 3 4 5 6 7 8 9 34 73

linux整理-19-Shell的基本语法(变量,运算符,流程控制,数组,函数)_第16张图片

7、跨脚本调用函数

编写一个base.sh脚本,里面放放一个test函数

#!/bin/bash
test(){
        echo "hello"
}

再编写一个other.sh脚本,里面引入base.sh脚本,并且调用test函数:

#!/bin/bash
. /home/linux/bin/base.sh  ## 引入脚本
test    ##调用引入脚本当中的test函数

效果:
在这里插入图片描述

你可能感兴趣的:(linux学习)