Linux之Shell脚本

目录

1.Linux Shell简介

1.1.Shell概述

1.2.Shell基本格式

1.3.Shell执行方式

1.3.1. sh方式或者bash方式

1.3.2. source方式或者 . 命令方式

1.3.3.直接执行该脚本文件

1.4.Shell注释

2.Shell基本语法

2.1.变量

2.1.1.系统变量

2.1.2.自定义变量

2.1.3.特殊变量

2.2.运算符

2.2.1.算术运算符

2.2.2.关系运算符

2.2.3.布尔运算符

2.2.4.字符串运算符

2.2.5.文件运算符

2.3.流程控制

2.3.1.if

2.3.2.while

2.3.3.case

2.3.4.for

2.3.5.until

2.4.数组

2.5.函数使用

2.6.函数参数

2.7.跨脚本调用函数

3.Shell综合案例

3.1.打印九九乘法表

3.2.自动部署集群的JDK

4.总结


1.Linux Shell简介

1.1.Shell概述

Shell本身是一个用C语言编写的程序,它是用户使用Unix/Linux的桥梁,用户的大部分工作都是通过Shell完成的。

Shell既是一种命令语言,又是一种程序设计语言。作为命令语言,它交互式地解释和执行用户输入的命令。作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。

Shell它虽然不是Unix/Linux系统内核的一部分,但它调用了系统核心的大部分功能来执行程序、建立文件并以并行的方式协调各个程序的运行。Shell是用户与内核进行交互操作的一种接口,目前最流行的Shell称为bash Shell(Bourne Again Shell)。

Shell是一门编程语言(解释型),即shell脚本(就是用在Linux的shell命令编程),shell脚本程序从脚本中一行一行读取并执行这些命令,相当于一个用户把脚本中的命令一行一行敲到Shell提示符下执行。

Shell是一种脚本语言,那么,就必须有解释器来执行这些脚本。Unix/Linux上常见的Shell脚本解释器有bash、sh、csh、ksh等,习惯是把它们称作一种Shell。我们常说有多少种Shell,其实说的是Shell脚本解释器,可以通过cat /etc/shells 命令查看系统中安装的shell,不同的shell可能支持的命令语法是不同的。

sh是Unix标准默认的shell,由Steve Bourne开发,是Bourne Shell的缩写。

bash是Linux标准默认的shell,本教程也基于bash讲解。bash由Brian Fox和Chet Ramey共同完成,是Bourne Again Shell的缩写。

Shell本身支持的命令并不多,内部命令一共有40个,但是它可以调用其他的程序,每个程序就是一个命令,这使得Shell命令的数量可以无限扩展,其结果就是Shell的功能非常强大,完全能够胜任Linux的日常管理工作,如文本或字符串检索、文件的查找或创建、大规模软件的自动部署、更改系统设置、监控服务器性能、发送报警邮件、抓取网页内容、压缩文件等。

1.2.Shell基本格式

代码写在普通文件中,通常以.sh结尾,虽然不是强制要求,但希望大家最好这么做。

例子:

[root@hadoop02 bin]# vim helloworld.sh

编辑文件内容如下:

#!/bin/bash ##指定默认解释器,若执行时指定了解释器,则该句无效

echo "hello world" ##注释也可以写这里

保存退出即可

在这里,我们就写好了一个shell脚本,第一行是固定需要的,表明用哪一种shell解释器来执行我们的这个脚本程序。本质上,shell脚本里面的代码就是一些流程控制语句加一些特殊语法再加shell命令组成。其中,我们可以当做每一个命令就是shell编程当中的关键字。

1.3.Shell执行方式

1.3.1. sh方式或者bash方式

sh helloworld.sh

bash helloworld.sh ##直接指定系统默认的bash shell解释执行

1.3.2. source方式或者 . 命令方式

source命令也称为“点命令”,也就是一个点符号(.),是bash的内部命令。

功能:使Shell 先读入指定的Shell 程序文件,再依次执行文件中的所有语句。

source命令通常用于重新执行刚修改的初始化文件,比如/etc/profile文件,使之立即生效,而不必注销并重新登录。

用法:source filename 或 . filename

示例:

[root@hadoop02 bin]# . helloworld.sh

[root@hadoop02 bin]# source helloworld.sh

注意: . 和脚本名称之间是有空格的

1.3.3.直接执行该脚本文件

可以有2种方式,不过这2种方式都需要该文件有执行权限。

方式一:相对路径

[root@hadoop02 ~]# ./helloworld.sh

方式二:绝对路径

[root@hadoop02 ~]# /root/helloworld.sh

1.4.Shell注释

单行注释:Shell脚本中以#开头的代码就是注释

多行注释:Shell脚本中也可以使用多行注释,格式: :<<! 注释文字 !

 

2.Shell基本语法

2.1.变量

2.1.1.系统变量

Linux Shell中的变量分为“系统变量“和”用户自定义变量“。系统变量可以通过set命令来查看,用户环境变量可以通过env查看。

常用的系统变量:$PWD $SHELL $USER $HOME。

2.1.2.自定义变量

1. 语法

变量=值(例如:STR=abc)

##等号两侧不能有空格

##变量名一般习惯为大写

##使用变量:STR

echo $STR

echo '$STR'

echo "$STR"

2. 示例

 

解释

命令: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脚本的变量?

[root@hadoop02 bin]# vi a.sh

#!/bin/bash

A="A in a.sh"

echo $A

echo $B

/root/bin/b.sh

[root@hadoop02 bin]# vi b.sh

#!/bin/bash

B="B in b.sh"

echo $A

echo $B

执行 ./a.sh之后的结果:

在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 /roo/bin` ##反引号,运行里面的命令,并把结果返回给变量a

另一种写法:a=$(ls -l /root/bin)

5. 变量有用技巧

${var} #变量本来的值

${var:-word} #如果变量var为空或已被删除(unset),那么返回word,但不改变var的值

${var:+word} #如果变量var被定义,那么返回word,但不改变var的值

${var:=word} #如果变量var为空或已被删除,那么返回word,并将var的值设置为word

${var:?message} #如果变量 var 为空或已被删除(unset),那么将消息 message 送到标准错误输出,可以用来检测变量 var 是否可以被正常赋值。若此替换出现在Shell脚本中,那么脚本将停止运行。

 

2.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 $?

$*与$@区别:

  1. $* 和 $@ 都表示传递给函数或脚本的所有参数。
  2. 不被双引号" "包含时,$* 和 $@ 都以$1 $2 … $n 的形式组成参数列表。
  3. 当它们被双引号" "包含时,
    1. "$*" 会将所有的参数作为一个整体,以"$1 $2 … $n"的形式组成一个整串;
    2. "$@" 会将各个参数分开,以"$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

 

2.2.运算符

2.2.1.算术运算符

1.用exper

2.用(( ))

3.用$[ ]

4.用let

5.注意:以上命令都只对整型值有效,不适用于浮点数

 

如果有浮点数参与运算,可以将echo与bc命令结合起来使用,格式如下:

 

且看bc的一些强大作用:

[root@hdp1 ~]# echo "1.121*3" | bc

3.363

[root@hdp1 ~]# echo "scale=2;3/8" | bc

.37

[root@hdp1 ~]# echo "obase=2;127" | bc

1111111

[root@hdp1 ~]# echo "obase=10;ibase=2;101111111" | bc

383

[root@hdp1 ~]# echo "10^10" | bc

10000000000

[root@hdp1 ~]# echo "sqrt(100)" | bc

10

除了用bc做进制转换以外,还可以这样做:

echo $((base#number))

例子:

[root@hdp1 ~]# echo $((8#377))

255

[root@hdp1 ~]# echo $((025))

21

[root@hdp1 ~]# echo $((0xA4))

164

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

[root@hdp1 ~]# echo "1.2<2" | bc

1

[root@hdp1 ~]# echo "1.2>2" | bc

0

[root@hdp1 ~]# echo "1.2==2" | bc

0

[root@hdp1 ~]# echo "1.2!=2" | bc

1

三元运算符:

[root@hdp1 ~]# [ $(echo "1.2>2" | bc) -eq 1 ] && echo yes || echo no

no

[root@hdp1 ~]# [ $(echo "1.2<2" | bc) -eq 1 ] && echo yes || echo no

yes

 

2.2.2.关系运算符

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

运算符

等同运算符

说明

-eq

==

检测两个数据是否相等,相等返回true

-ne

!=

检测两个数据是否相等,不等返回true

-ge

>=

检测左边的数据是否大于等于右边的,若是,则返回true

-gt

>

检测左边的数据是否大于右边的,若是,则返回true

-le

<=

检测左边的数据是否小于等于右边的,若是,则返回true

-lt

<

检测左边的数据是否小于右边的,若是,则返回true

 

2.2.3.布尔运算符

下面给出一张布尔运算符列表:

运算符

等同运算符

说明

!

!

非运算,表达式为true,则返回false,否则返回true

-a

&&

与运算,两个表达式都为true,则返回true

-o

||

或运算,有一个表达式为true,则返回true

 

2.2.4.字符串运算符

下面给出一张字符串运算符列表:

运算符

说明

=

检测两边字符串是否相等,相等返回true

!=

检测两边字符串是否相等,不相等返回true

-z

检测字符串的长度是否为0,为0返回true

-n

检测字符串的长度是否为0,不为0返回true

str

检测字符串是否为空,不为空返回true

 

2.2.5.文件运算符

下面给出一张文件运算符列表:

运算符

说明

-d

检测文件是否为目录,若是,则返回true

-f

检测文件是否为普通文件(既不是目录,也不是设备文件),若是,则返回true

-e

检测文件(或目录)是否存在,若是,则返回true

-s

检测文件是否为空(文件大小大于0),若不为空,则返回true

-r

检测文件是否可读,若是,则返回true

-w

检测文件是否可以写,若是,则返回true

-x

检测文件是否可执行,若是,则返回true

-b

检测文件是否为块设备文件,若是,则返回true

-c

检测文件是否为字符设备文件,若是,则返回true

 

2.3.流程控制

2.3.1.if

1. 语法格式

if[ condition ]

then

statements

elif[ condition ]

then

statements

else

statements

fi

2. 示例程序

#!/bin/bash

read -p "please your name:" NAME

if [ $NAME = root ]

then echo "hello ${NAME},welcome!"

elif [ $NAME = hdp01 ]

then echo "hello ${NAME},welcome!"

else

echo "I do not know yue!"

fi

注意事项

  1. if 与 [ ] 以空格间隔,elif 与 [ ] 以空格间隔
  2. 条件前后和中括号以空格间隔
  3. 判断是否相等用 = ,而其前后以空格间隔(有时间总结下什么时候需要空格,什么时候不需要空格。

3. 规则解释

[ condition ] (注:condition前后要有空格)

#非空返回true,可使用$?验证(0为true,>1为false)

[ hadoop ]

#空返回false

[root@hdp1 ~]# a=2

[root@hdp1 ~]# b=2

[root@hdp1 ~]# [ a = b ]

[root@hdp1 ~]# echo $?

1

[root@hdp1 ~]# [ $a = $b ]

[root@hdp1 ~]# echo $?

0

[root@hdp1 ~]# [ ]

[root@hdp1 ~]# echo $?

1

[root@hdp1 ~]# [ $a ]

[root@hdp1 ~]# echo $?

0

[root@hdp1 ~]# if [ a = b ];then echo ok;else echo notok;fi

notok

[root@hdp1 ~]# if [ $a = $b ];then echo ok;else echo notok;fi

ok

[root@hdp1 ~]# if [ a=b ];then echo ok;else echo notok;fi

ok

[root@hdp1 ~]# if [a=b];then echo ok;else echo notok;fi

-bash: [a=b]: command not found

notok

短路运算符(理解为三元运算符)

[ condiiton ] && ehco OK || echo NotOK

#条件满足,执行&&后面的语句;条件不满足,执行||后面的语句

[root@hdp1 ~]# [ a = b ] && ehco OK || echo NotOK

NotOK

[root@hdp1 ~]# [ $a = $b ] && echo OK || echo NotOK

OK

条件判断组合

条件判断组合有2种使用方式:[] 和 [[]]

注意它们的区别:

[[ ]]中逻辑组合使用&& || 符号

[ ]中逻辑组合使用 -a -o

[root@hdp1 ~]# if [ a = b -a b = b ];then echo ok;else echo notok;fi

notok

[root@hdp1 ~]# if [ a = b -o b = b ];then echo ok;else echo notok;fi

ok

[root@hdp1 ~]# if [[ a = b && b = b ]];then echo ok;else echo notok;fi

notok

[root@hdp1 ~]# if [[ a = b || b = b ]];then echo ok;else echo notok;fi

ok

常用判断运算:

1. 字符串比较

= 判断相等

!= 判断不相等

-z 字符串长度为0,返回true

-n 字符串长度不为0,返回true

[root@hdp1 ~]# if [ 'aa' = 'bb' ];then echo ok;else echo notok;fi

notok

[root@hdp1 ~]# if [ 'aa' != 'bb' ];then echo ok;else echo notok;fi

ok

[root@hdp1 ~]# if [ -z 'aa' ];then echo ok;else echo notok;fi

notok

[root@hdp1 ~]# if [ -n 'aa' ];then echo ok;else echo notok;fi

ok

[root@hdp1 ~]# if [ -z '' ];then echo ok;else echo notok;fi

ok

[root@hdp1 ~]# if [ -z ' ' ];then echo ok;else echo notok;fi

notok

[root@hdp1 ~]# if [ -n ' ' ];then echo ok;else echo notok;fi

ok

[root@hdp1 ~]# if [ -n '' ];then echo ok;else echo notok;fi

notok

2. 整数比较

-lt 小于 less than

-le 小于等于

-eq 等于

-gt 大于 great than

-ge 大于等于

-ne 不等于

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

ok

3. 文件判断

-d 是否为目录

-f 是否为文件

-e 是否存在

[root@hdp1 ~]# if [ -d /bin ];then echo ok;else echo notok;fi

ok

[root@hdp1 ~]# if [ -f /bin/ls ];then echo ok;else echo notok;fi

ok

[root@hdp1 ~]# if [ -e /bin/ls ];then echo ok;else echo notok;fi

ok

2.3.2.while

1. 语法格式

while expresion

do

command

……

done

2. 示例程序

#!/bin/bash

i=1

while ((i<=3))

do

echo $i

let i++

done

#!/bin/bash

i=1

while [ $i -le 3 ]

do

echo $i

i=$((i+1))

done

 

 

2.3.3.case

2.3.4.for

1. 语法格式

for 变量 in 列表

do

command

……

done

2. 三种方式

方式一:

#!/bin/bash

for N in 1 2 3

do

echo $N

done

或者 for N in 1 2 3;do echo $N;done;

方式二:

[root@hdp1 ~]# for N in {1,2,3};do echo $N;done;

1

2

3

方式三:

[root@hdp1 ~]# for ((i=1;i<=3;i++));do echo "welcome ${i} time";done;

welcome 1 time

welcome 2 time

welcome 3 time

或者

#!/bin/bash

for ((i=1;i<=3;i++))

do

echo "welcome ${i} time"

done

2.3.5.until

1. 语法格式

until expression

do

command

……

done

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

2. 示例程序

#!/bin/bash

a=0

until [ $a -gt 3 ]

do

echo $a

a=$((a+1))

done

 

 

2.4.数组

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

array_name=(value1 … valuen)

读取数组元素的格式是:${array_name[index]}

示例:

[root@hdp1 ~]# mingxing=(huangbo xuzheng wangbaoqiang)

[root@hdp1 ~]# echo $mingxing

huangbo

[root@hdp1 ~]# echo ${mingxing[2]}

wangbaoqiang

[root@hdp1 ~]# mingxing[3]=liujialing

[root@hdp1 ~]# echo ${mingxing[3]}

liujialing

[root@hdp1 ~]# echo ${mingxing[*]}

huangbo xuzheng wangbaoqiang liujialing

[root@hdp1 ~]# echo ${!mingxing[*]}

0 1 2 3

[root@hdp1 ~]# echo ${#mingxing[*]}

4

获取数组下标

[root@hdp1 ~]# echo ${!mingxing[*]}

0 1 2 3

[root@hdp1 ~]# echo ${!mingxing[@]}

0 1 2 3

输出数组所有元素

[root@hdp1 ~]# echo ${mingxing[*]}

huangbo xuzheng wangbaoqiang liujialing

[root@hdp1 ~]# echo ${mingxing[@]}

huangbo xuzheng wangbaoqiang liujialing

获取数组的长度

[root@hdp1 ~]# echo ${#mingxing[*]}

4

[root@hdp1 ~]# echo ${#mingxing[@]}

4

数组对接

[root@hdp1 ~]# mingxing+=(liyifei liuyufeng)

[root@hdp1 ~]# echo ${mingxing[*]}

huangbo xuzheng wangbaoqiang liujialing liyifei liuyufeng

删除数组元素:但是会保留对应的位置,就是该值的下标依然保留,会空着,之后还可填充值进来。

[root@hdp1 ~]# unset mingxing[0]

[root@hdp1 ~]# echo ${mingxing[*]}

xuzheng wangbaoqiang liujialing liyifei liuyufeng

[root@hdp1 ~]# echo ${!mingxing[*]}

1 2 3 4 5

[root@hdp1 ~]# echo ${mingxing[0]}

 

[root@hdp1 ~]# echo ${mingxing[1]}

xuzheng

遍历数组

#!/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 index in ${!IP[*]}

do

echo ${IP[$index]}

done

数组的分片

${arr[@]:number1:length}

这里number1表示从下标number1开始取值,length表示往后去几个元素,即取到的新数组的长度。

[root@hdp1 ~]# arr=(1 2 3 4 5 6 7 8 9)

[root@hdp1 ~]# echo ${arr[@]:0:3}

1 2 3

 

2.5.函数使用

函数的语法使用示例

#!/bin/bash

hello(){

echo "`date +%Y-%m-%d`"

return 2

}

#调用函数及获取返回值

hello

echo $?

 

[root@hdp1 ~]# . a.sh

2018-10-31

2

 

函数调用方式直接写函数名就OK了!

注意

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

脚本调试

使用-x选项跟踪脚本调试shell脚本,能打印所执行的每一行命令以及当前状态,比如:

sh -x a.sh 或在代码中加入:set -x

[root@hdp1 ~]# sh -x a.sh

+ hello

++ date +%Y-%m-%d

+ echo 2018-10-31

2018-10-31

+ return 2

+ echo 2

2

 

2.6.函数参数

#!/bin/bash

funcWithParam(){

echo "第一个参数为$1!"

echo "第二个参数为$2!"

echo "第十个参数为$20!"

echo "第十个参数为${10}!"

echo "第十一个参数为${11}!"

echo "参数总数有$#个!"

echo "作为一个字符串输出所有参数$*!"

}

funcWithParam 1 2 3 4 5 6 7 8 9 34 73

[root@hdp1 ~]# . a.sh

第一个参数为1!

第二个参数为2!

第十个参数为20!

第十个参数为34!

第十一个参数为73!

参数总数有11个!

作为一个字符串输出所有参数1 2 3 4 5 6 7 8 9 34 73!

 

2.7.跨脚本调用函数

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

[root@hdp1 ~]# vim base.sh

#!/bin/bash

test(){

echo "hello"

}

[root@hdp1 ~]# vim other.sh

#!/bin/bash

. /root/base.sh ##引入脚本

test ##调用引入脚本当中的test函数

[root@hdp1 ~]# . other.sh

hello

 

3.Shell综合案例

3.1.打印九九乘法表

示例代码:

#!/bin/bash

for((i=1;i<=9;++i))

do

for((j=1;j<=i;j++))

do

echo -ne "$i*$j=$((i*j))\t"

done

echo

done

解释说明:

-n 不加换行符

-e 解释转义符

echo 换行

 

3.2.自动部署集群的JDK

1.需求描述

公司内有一个N台节点的集群,需要统一安装一些软件(jdk)。需要开发一个脚本,实现对集群中的N台节点批量自动下载、安装jdk。

2.思路

我们现在有一个JDK安装包在一台服务器上。那我们要实现这个目标:

  1. 把包传到每台服务器,或者通过本地yum源的方式去服务器上取。
  2. 给每台节点发送一个安装脚本,并且让脚本自己执行。
  3. 需要写一个启动脚本,用来执行以上两步操作。

3.expect使用

蛋疼点:假如在没有配置SSH免密登录的前提下,我们要使用scp命令从一台机器拷贝文件夹都另外的机器,会有人机交互的过程,那我们怎么让机器自己实现人机交互?

灵丹妙药:expect

 

命令

描述

set

可以设置超时,也可以设置变量

timeout

超时等待时间,默认10s

spawn

执行一个命令

expect " "

匹配输出的内容

exp_continue

继续执行下面匹配

 

思路:模拟该人机交互过程,在需要交互的情况下,通过我们的检测给输入提前准备好值即可。

示例:观看配置SSH免密登录过程。

实现脚本:

[root@hadoop02 bin]# vi testExpect.sh

#!/bin/bash

## 定义一个函数

sshcopyid(){

expect -c "

spawn ssh-copy-id $1

expect {

\"(yes/no)?\" {send \"yes\r\";exp_continue}

\"password:\" {send \"$2\r\";exp_continue}

}

"

}

## 调用函数执行

sshcopyid $1 $2

注意:如果机器没有expect,则请先安装expect:yum install -y expect

 

4.脚本实现

1. 启动脚本initInstallJDK.sh

#!/bin/bash

SERVERS="192.168.123.201"

PASSWORD=hadoop

BASE_SERVER=192.168.123.202

auto_ssh_copy_id() {

expect -c "set timeout -1;

spawn ssh-copy-id $1;

expect {

*(yes/no)* {send -- yes\r;exp_continue;}

*password:* {send -- $2\r;exp_continue;}

eof {exit 0;}

}";

}

ssh_copy_id_to_all() {

for SERVER in $SERVERS

do

auto_ssh_copy_id $SERVER $PASSWORD

done

}

ssh_copy_id_to_all

for SERVER in $SERVERS

do

scp installJDK.sh root@$SERVER:/root

ssh root@$SERVER chmod 755 installJDK.sh

ssh root@$SERVER /root/installJDK.sh

done

2. 安装脚本installJDK.sh

#!/bin/bash

BASE_SERVER=192.168.123.202

yum install -y wget

wget $BASE_SERVER/soft/jdk-8u73-linux-x64.tar.gz

tar -zxvf jdk-8u73-linux-x64.tar.gz -C /usr/local

cat >> /etc/profile << EOF

export JAVA_HOME=/usr/local/jdk1.8.0_73

export PATH=\$PATH:\$JAVA_HOME/bin

EOF

 

4.总结

写脚本注意事项:

1.开头加解释器:#!/bin/bash 和注释说明。

2.命名建议规则:变量名大写、局部变量小写、函数名小写,名字体现出实际作用。

3.默认变量是全局的,在函数中变量local指定为局部变量,避免污染其他作用域。

4.set -e 遇到执行非0时退出脚本,set -x 打印执行过程。

5.写脚本一定要先测试再到生产上。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值