初识shell

什么是shell

  • shell程序:接口,提供了用户和内核交互桥梁。

  • shell语言: 命令语言,编程语言。解释性语言(编译型语言) 。用于编写shell脚本。

  • shell解释器:  sh(unix默认)  bash(linux默认)

shell基本格式

1
2
3
4
#!/bin/bash
#设置默认的shell解释器,如果指定使用某个解释器执行,则此行不生效
echo aa
# echo bb

shell脚本执行

指定解释器执行

  • sh 脚本名称

  • bash 脚本名称

1
2
3
4
[hadoop@hadoop01 test]$ sh shell01.sh
aa
[hadoop@hadoop01 test]$ bash shell01.sh
aa

内部命令

  • source. 脚本名称

    • .:使Shell读入指定的Shell程序文件. 并依次执行文件中的所有语句(脚本调用另外脚本)

    • source:用于重新执行刚修改的初始化文件,使之立即生效,而不必注销并重新登录

      1
      2
      3
      4
      [hadoop@hadoop01 test]$ . shell01.sh
      aa
      [hadoop@hadoop01 test]$ source shell01.sh
      aa

通过路径执行

  • 需要有执行的权限

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    [hadoop@hadoop01 test]$ ll
    total 4
    -rw-rw-r-- 1 hadoop hadoop 21 Aug 5 01:58 shell01.sh

    # 修改权限 chmod 755 a.sh
    [hadoop@hadoop01 test]$ chmod u+x shell01.sh

    [hadoop@hadoop01 test]$ ll
    total 4
    -rwxrw-r-- 1 hadoop hadoop 21 Aug 5 01:58 shell01.sh

    # 相对路径
    [hadoop@hadoop01 test]$ ./shell01.sh
    aa

    # 绝对路径
    [hadoop@hadoop01 test]$ /home/hadoop/test/shell01.sh
    aa

shell注释

  • 单行注释:shell中以#号开头表示

  • 多行注释::<<! 多行注释 !

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [hadoop@hadoop01 test]$ cat shell01.sh
    #!/bin/bash
    echo aa
    # echo bb
    :<<!
    echo '1'
    echo '2'
    echo '3'
    !

    [hadoop@hadoop01 test]$ ./shell01.sh
    aa

变量

  • Shell中按照变量的作用域和生命周期,Shell变量可分为四大类:

    1. 永久环境变量:需要修改配置文件,变量永久生效

      • /etc/profile:所有用户有效

      • ~/.bash_profile: 当前用户永久有效 ,立即生效需要source /etc/profile

    2. 临时环境变量:使用export命令行声明即可,变量在shell脚本进程结束后仍然有效,但在关闭当前shell会话后失效

    3. 全局变量:在脚本中定义,仅在当前Shell脚本中有效,其他Shell脚本进程不能访本

      • 作用域从定义的位置开始,到脚本结束或被显示删除的地方为止。

      • 注意,全局变量既可以在Shell函数内定义,也可以在shell函数外定义

      • 因为shell函数内定义的变量默认为global,且作用域从“函数被调用时执行变量定义的地方”开始,到脚本结束或被显示删除的地方为止。

    4. 局部变量。在shell脚本中函数内显示使用local关键字定义的变量。其作用域局限于函数内。同名local变量会屏蔽global变量。

  • 系统的内置变量:

    • 查看 : set ;

    • 取出: echo $USER,echo $PATH

      1
      2
      3
      4
      5
      6
      7
      8
      # 查看内置变量
      [hadoop@hadoop01 ~]$ set
      BASH=/bin/bash
      ....

      # 使用$取出
      [hadoop@hadoop01 ~]$ echo $BASH
      /bin/bash
  • 自定义变量变量名=值:

    • 规范:

      1. =号附近不能用空格
      2. 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。变量名推荐使用大写字母
      3. 变量名不能使用标点符号。
      4. 变量名不能使用bash里的关键字(可用help命令查看保留关键字)。
      5. 单引号: 内部不能取值,(会脱意)
      6. 双引号: 内部可以取值,,可以出现转义字符
    • 例子

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      [hadoop@hadoop01 ~]$ A='this is a'
      [hadoop@hadoop01 ~]$ echo $A
      this is a

      [hadoop@hadoop01 ~]$ B='this is b'
      [hadoop@hadoop01 ~]$ echo $B
      this is b

      # 双引号: 内部可以取值
      [hadoop@hadoop01 ~]$ echo "$A"
      this is a

      # 单引号: 内部不能取值
      [hadoop@hadoop01 ~]$ echo '$A'
      $A

      # 已定义的变量,可以被重新定义
      [hadoop@hadoop01 ~]$ your_name="tom"
      [hadoop@hadoop01 ~]$ echo $your_name
      tom
      [hadoop@hadoop01 ~]$ your_name="alibaba"
      [hadoop@hadoop01 ~]$ echo $your_name
      alibaba
    • 使用变量的时候才加美元符($),第二次赋值的时候不能写$

    • 只读变量:使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      [hadoop@hadoop01 ~]$ myUrl="https://www.google.com"
      # 设置只读变量
      [hadoop@hadoop01 ~]$ readonly myUrl
      [hadoop@hadoop01 ~]$ myUrl="https://www.runoob.com"
      -bash: myUrl: readonly variable


      # 定义的时候设置只读变量(不可删除和修改)
      # readonly 变量名=变量值
      [hadoop@hadoop01 ~]$ readonly site='https://baidu.com'
      [hadoop@hadoop01 ~]$ site='https://www.baidu.com'
      -bash: site: readonly variable
    • 删除变量 :使用 unset 命令可以删除变量。语法:unset variable_name

      • 变量被删除后不能再次使用。unset 命令不能删除只读变量。

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        [hadoop@hadoop01 ~]$ readonly site='https://baidu.com'
        # 不能删除只读变量。
        [hadoop@hadoop01 ~]$ unset site
        -bash: unset: site: cannot unset: readonly variable

        # 变量被删除后不能再次使用
        [hadoop@hadoop01 ~]$ echo $A
        this is a
        [hadoop@hadoop01 ~]$ unset A
        [hadoop@hadoop01 ~]$ echo $A

        [hadoop@hadoop01 ~]$

变量案例

  • 使用解释器和路径执行则会开启新的Shell进程来执行指定的脚本,这样的话,父进程中的变量在子进程中就无法访问,子进程也无法访问父进程内容

  • 使用解释器和路径的方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    # a.sh
    [hadoop@hadoop01 test]$ cat a.sh
    #!/bin/bash
    A='A in a.sh'
    echo $A
    # 创建子进程读取b.sh
    /home/hadoop/test/b.sh
    # 使用内部命令执行,b.sh内容读到父进程
    #. /home/hadoop/test/b.sh
    echo $B

    # b.sh
    [hadoop@hadoop01 test]$ cat b.sh
    #!/bin/bash
    B='B in b.sh'
    echo $B
    echo $A

    # 路径执行或使用解析器开启新的Shell进程
    # a.sh中只有A变量 b.sh中只有B变量
    # b.sh不能访父空间的非export中的变量
    [hadoop@hadoop01 test]$ bash a.sh # ./a.sh 效果相同
    A in a.sh
    B in b.sh # b.sh脚本输出B的结果
    #空行 b.sh输出A的结果
    #空行 a.sh输出B的结果
    [hadoop@hadoop01 test]$ bash b.sh # ./b.sh 效果相同
    B in b.sh
    #空行 b.sh中只有B变量没有A变量

    #------使用一个终端运行:结果有问题--------------------

    # 使用内部命令 这里会用同一个空间运行,运行后就会有A或者B,会产生下面的效果
    # 实际上需要开二个终端分别运行a.sh 和 b.sh,实际只有二行
    [hadoop@hadoop01 test]$ . a.sh # source a.sh 效果相同
    A in a.sh
    B in b.sh

    B in b.sh
    # 实际上需要开二个终端分别运行a.sh 和 b.sh,实际只有一行
    [hadoop@hadoop01 test]$ . b.sh # source b.sh 效果相同
    B in b.sh
    A in a.sh
    [hadoop@hadoop01 test]$
  • 使用内部命令的方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    [hadoop@hadoop01 test]$ pwd
    /home/hadoop/test
    [hadoop@hadoop01 test]$ cat a.sh
    #!/bin/bash
    A='A in a.sh'
    echo $A
    # 使用内部命令执行,b.sh内容读到父进程
    . /home/hadoop/test/b.sh
    echo $B
    [hadoop@hadoop01 test]$ cat b.sh
    #!/bin/bash
    B='B in b.sh'
    echo $B
    echo $A

    # 解释器的方式: b.sh在a.sh空间中运行
    [hadoop@hadoop01 test]$ bash a.sh # ./a.sh
    A in a.sh
    B in b.sh
    A in a.sh
    B in b.sh
    # b.sh中只有B变量
    [hadoop@hadoop01 test]$ bash b.sh # ./b.sh
    B in b.sh

    #------使用一个终端运行:结果有问题--------------------

    # 内部命令: a.sh和b.sh 都在当前进程中运行
    [hadoop@hadoop01 test]$ source a.sh # . a.sh
    A in a.sh
    B in b.sh
    A in a.sh
    B in b.sh
    # 需要重新开终端测试,
    # 否则a.sh和b.sh 都在当前进程中运行,A和B变量都能被二个脚本访问,实际只有B这一行
    [hadoop@hadoop01 test]$ source b.sh # . b.sh
    B in b.sh
    A in a.sh
  • 使用内部命令执行总结:

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

export命令

使用export命令我们申明的是临时环境变量,在当前shell会话中,所有的shell实例都可以访问由export命令申明的临时环境变量。

因为当前shell会话中的所有shell实例,都是当前shell会话的子进程,所以可以与父进程一同访问环境变量。

  • hell变量可分为四大类:

    • 永久环境变量
    • 临时环境变量
    • 全局变量
    • 局部变量
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    [hadoop@hadoop01 test]$ cat c.sh
    #!/bin/bash
    name='Lily'
    # 让d.sh在c.sh空间运行
    bash d.sh
    [hadoop@hadoop01 test]$ cat d.sh
    #!/bin/bash
    echo $name
    # 不使用export命令,取不到结果
    [hadoop@hadoop01 test]$ bash c.sh

    # 使用export命令后,d.sh可以读到dinginess的临时变量
    [hadoop@hadoop01 test]$ cat c.sh
    #!/bin/bash
    export name='tom'
    #name='Lily'
    # 让d.sh在c.sh空间运行
    bash d.sh
    [hadoop@hadoop01 test]$ bash c.sh
    tom

反引号赋值

  • 先将反引号内结果运算完毕,然后赋值,也可以用$()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 反引号赋值
    [hadoop@hadoop01 test]$ DATE1=`date`
    [hadoop@hadoop01 test]$ echo $DATE1
    Wed Aug 5 04:10:19 CST 2020

    # $()赋值
    [hadoop@hadoop01 test]$ DATE2=$(date)
    [hadoop@hadoop01 test]$ echo $DATE2
    Wed Aug 5 04:10:53 CST 2020

    # 输出家目录下的文件
    [hadoop@hadoop01 test]$ B=`ll ~/`
    [hadoop@hadoop01 test]$
    [hadoop@hadoop01 test]$ echo $B
    total 404020 drwxrwxr-x. 3 hadoop hadoop 26 Aug 5 03:40 apps drwxrwxr-x 3 hadoop hadoop 24 Jul 31 00:06 data -rw-rw-r--. 1 hadoop hadoop 218720521 Jul 16 14:40 hadoop-2.7.7.tar.gz -rw-rw-r--. 1 hadoop hadoop 194990602 Jun 4 2019 jdk-8u211-linux-x64.tar.gz drwxrwxr-x 2 hadoop hadoop 72 Aug 5 04:01 test

${}取变量其他技巧

  • ${var:-aa}:没有值时输出aa
  • ${var:+aa}:有值时输出aa
  • ${var:=aa}:没有值时赋值为aa
  • ${var:?aa}:检测变量是否有值,var为空或者被删除(unset),message会送到标准输出,出现在shell脚本中,脚本会停止运行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[hadoop@hadoop01 test]$ A='百度'
# 有值时输出
[hadoop@hadoop01 test]$ echo ${A:+Google}
Google
[hadoop@hadoop01 test]$ A=''
# 没有值时输出,不会赋值
[hadoop@hadoop01 test]$ echo ${A:-百度}
百度
[hadoop@hadoop01 test]$ echo $A

# 没有值时赋值
[hadoop@hadoop01 test]$ echo ${A:=腾讯}
腾讯
[hadoop@hadoop01 test]$ echo $A
腾讯
# 为空或者被删除(unset),message会送到标准输
[hadoop@hadoop01 test]$ echo ${A:?我是一个消息}
腾讯
[hadoop@hadoop01 test]$ unset A
[hadoop@hadoop01 test]$ echo ${A:?我是一个消息}
-bash: A: 我是一个消息

特殊变量

  • 脚本执行的时候需要传递参数,参数用空格隔开,尽量使用${}

  • 特殊变量列表

    变量表达式 含义
    $0 当前脚本的文件名
    $n 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。
    $# 传递给脚本或函数的参数个数。
    $* 传递给脚本或函数的所有参数。
    $@ 传递给脚本或函数的所有参数。被双引号(“ “)包含时,与 $* 稍有不同,下面将会讲到。
    $? 上个命令的退出状态,或函数的返回值。
    $$ 当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程 ID。
  • 例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    [hadoop@hadoop01 test]$ cat e.sh
    #!/bin/bash
    echo $? # 上个命令的退出状态
    echo $$ # 脚本所在的进程 ID
    echo $0 # 脚本名
    echo $1 # 第一个参数
    echo $2 # 第二个参数
    echo $# # 参数个数
    echo $* # 传递给脚本或函数的所有参数
    echo $@ # 传递给脚本或函数的所有参数
    [hadoop@hadoop01 test]$ bash e.sh a1 a2 a3
    0
    2544
    e.sh
    a1
    a2
    3
    a1 a2 a3
    a1 a2 a3

$*和$@的区别

  • echo的每一句输出默认会换行

  • $* 和 $@ 都表示传递给函数或脚本的所有参数

  • 没有双引号" ": 二者都以$1 $2 ... $n的形式组成参数列表

  • 有引号的时候:

    • $*将所有的参数作为一个整体 ,以"$1 $2 ... $n"的形式组成一个整串

    • $@将所有的参数分开,以"$1" "$2" ... "$n"的形式组成一个参数列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
[hadoop@hadoop01 test]$ cat f.sh
#!/bin/bash
echo "======$* : 没引号================"
for A in $*
do
echo $A
done
echo "======$@ : 没引号================"
for A in $@
do
echo $A
done
echo "======"$*" : 有引号: 当成整体================"
for A in "$*"
do
echo $A
done
echo "======"$@" : 有引号================"
for A in "$@"
do
echo $A
done

# 运行
[hadoop@hadoop01 test]$ sh f.sh aa bb cc
======aa bb cc : 没引号================
aa
bb
cc
======aa bb cc : 没引号================
aa
bb
cc
======aa bb cc : 有引号: 当成整体================
aa bb cc
======aa bb cc : 有引号================
aa
bb
cc

运算符

算术运算符:

  • 在四则运算以及逻辑运算。必须保证运算符与算数之间有空格。
  • 四则运算也只能借助:let,expr,双括号(())等命令完成。

expr 运算:

二边要加空格,只能计算整数

  1. +:加

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # expr和运算符二边要加空格
    [hadoop@hadoop01 ~]$ A= expr 2 + 3
    5
    [hadoop@hadoop01 ~]$ A=expr 2 + 3
    -bash: 2: command not found
    [hadoop@hadoop01 ~]$ A= expr 2+3
    2+3
    [hadoop@hadoop01 ~]$ A= expr 2+ 3
    expr: syntax error
    [hadoop@hadoop01 ~]$ A= expr 2 +3
    expr: syntax error
  2. -:减

    1
    2
    3
    4
    5
    6
    7
    # expr和运算符二边要加空格
    [hadoop@hadoop01 ~]$ A= expr 2 - 3
    -1
    [hadoop@hadoop01 ~]$ A=expr 2 - 3
    -bash: 2: command not found
    [hadoop@hadoop01 ~]$ A= expr 2-3
    2-3
  3. \*:乘号需要转义

    1
    2
    3
    4
    5
    [hadoop@hadoop01 ~]$ A= expr 2 * 3
    expr: syntax error
    # 需要转义
    [hadoop@hadoop01 ~]$ A= expr 2 \* 3
    6
  4. /:没有小数点,类似取模

    1
    2
    3
    4
    [hadoop@hadoop01 ~]$ A= expr 4 / 2
    2
    [hadoop@hadoop01 ~]$ A= expr 3 / 2
    1
  5. () 括号运算需要转义

    • 使用转移符号括起来

      1
      2
      3
      [hadoop@hadoop01 ~]$ A=`expr \( 2 + 3 \) \* 4`
      [hadoop@hadoop01 ~]$ echo $A
      20

双括号

语法:表达式的空格要求不严格,双括号可以换成中括号[]

((表达式1,表达式2…))

特点:

  1. 在双括号结构中,所有表达式可以像c语言一样,如:a++,b–等。
  2. 双括号结构中,所有变量可以不加入:“$”符号前缀
  3. 双括号可以进行逻辑运算,四则运算
  4. 双括号结构 扩展了for,while,if条件测试运算
  5. 支持多个表达式运算,各个表达式之间用“,”分开
  6. 如果双括号带:$,将获得表达式值,赋值给左边变量。
  • 四则运算

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    [hadoop@hadoop01 ~]$ a=1
    [hadoop@hadoop01 ~]$ b=2
    [hadoop@hadoop01 ~]$ c=3
    # 双括号结构中,所有变量可以不加入:“$”符号前缀
    [hadoop@hadoop01 ~]$ (($a=$a+1))
    -bash: ((: 1=1+1: attempted assignment to non-variable (error token is "=1+1")
    [hadoop@hadoop01 ~]$ (($a=a+1))
    -bash: ((: 1=a+1: attempted assignment to non-variable (error token is "=a+1")
    # 加法
    [hadoop@hadoop01 ~]$ ((a=a+1))
    2
    [hadoop@hadoop01 ~]$ ((a=c-a))
    [hadoop@hadoop01 ~]$ echo $a
    2
    # 减法
    [hadoop@hadoop01 ~]$ ((a=c-a))
    [hadoop@hadoop01 ~]$ echo $a
    1
    # 乘法 : 结构内的空格不固定
    [hadoop@hadoop01 ~]$ ((d=2 *c))
    [hadoop@hadoop01 ~]$ echo $d
    6
    # 除法:取模
    [hadoop@hadoop01 ~]$ ((e=4/2))
    [hadoop@hadoop01 ~]$ echo $e
    2
    [hadoop@hadoop01 ~]$ ((e=3/2))
    [hadoop@hadoop01 ~]$ echo $e
    1
    # 自增
    [hadoop@hadoop01 ~]$ ((b=++b))
    [hadoop@hadoop01 ~]$ echo $b
    3
    # 自减
    [hadoop@hadoop01 ~]$ ((--b))
    [hadoop@hadoop01 ~]$ echo $b
    2
    # 双括号带:$,将获得表达式值,赋值给左边变量。
    [hadoop@hadoop01 ~]$ e=$((1+10))
    [hadoop@hadoop01 ~]$ echo $e
    11
    # 带括号运算
    [hadoop@hadoop01 ~]$ f=$(((1+2)*4))
    [hadoop@hadoop01 ~]$ echo $f
    12
    # 双括号可以换成中括号`[]`
    [hadoop@hadoop01 ~]$ f=$[(1+2)*3]
    [hadoop@hadoop01 ~]$ echo $f
    9
  • 逻辑运算

    1
    2
    3
    4
    5
    6
    7
    8
    [hadoop@hadoop01 ~]$ a=1
    [hadoop@hadoop01 ~]$ b="ab"
    [hadoop@hadoop01 ~]$ echo $((a>1?8:9))
    9
    [hadoop@hadoop01 ~]$ ((b!="a"))&& echo "err2";
    err2
    [hadoop@hadoop01 ~]$ ((a<2))&& echo "ok";
    ok
  • 扩展流程控制语句(逻辑关系式)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    # for运算
    [hadoop@hadoop01 ~]$ num=10
    [hadoop@hadoop01 ~]$ total=0
    [hadoop@hadoop01 ~]$ for((i=0;i<num;i++));
    > do
    > ((total+=i))
    > done
    [hadoop@hadoop01 ~]$ echo $total
    45
    # while运算
    [hadoop@hadoop01 ~]$ total=0
    [hadoop@hadoop01 ~]$ i=0
    [hadoop@hadoop01 ~]$ echo nuum
    nuum
    [hadoop@hadoop01 ~]$ echo $num
    10
    [hadoop@hadoop01 ~]$ while((i<=num))
    > do
    > ((total+=i,i++))
    > done

    # if 运算
    [hadoop@hadoop01 ~]$ if((total=45))
    > then
    > echo "OK"
    > fi
    OK
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #!/bin/sh

    num=100;
    total=0;

    for((i=0;i<=num;i++));
    do
    ((total+=i));
    done
    echo $total;

    total=0;
    i=0;
    while((i<=num));
    do
    ((total+=i,i++));
    done
    echo $total;

    if((total>=5050));then
    echo "ok";
    fi

let命令

当表达式中含有 Shell 特殊字符(例如 |)时,需要用双引号" "或者单引号' '将表达式包围起来。let后的表达式不能使用空格

1
2
3
4
5
6
7
8
# 语法格式为:
let 表达式
# 或者
let "表达式"
# 或者
let '表达式'

# 它们都等价于 ((表达式))。
  • 给变量 i 加 8:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    [c.biancheng.net]$ i=2
    # let i+=8 等同于 ((i+=8)),但后者效率更高。
    [c.biancheng.net]$ let i+=8
    [c.biancheng.net]$ echo $i
    10
    # let运算不能带空格
    [hadoop@hadoop01 ~]$ let i+ 5
    -bash: let: i+: syntax error: operand expected (error token is "+")
    [hadoop@hadoop01 ~]$ let sum= \(1+3\)*2
    -bash: let: sum=: syntax error: operand expected (error token is "=")

    # let带括号运算需要转义
    [hadoop@hadoop01 ~]$ let sum=\(1+3\)*2
    [hadoop@hadoop01 ~]$ echo $sum
    8
  • let 后面可以跟多个表达式。

    1
    2
    3
    4
    [c.biancheng.net]$ a=10 b=35
    [c.biancheng.net]$ let a+=6 c=a+b #多个表达式以空格为分隔
    [c.biancheng.net]$ echo $a $c
    16 51
1

A=expr \( 2 + 3 \) \* 4
echo $A

A=$((2+3)): 不用管空格

A=$[2+3]: 不用管空格

let A=2:

let D=A+C :省略$,不可以使用空格

let D=A++

  1. ()—> $((A+B)):可以不写$符号
  2. ()—> $[A+B]:
  3. ()—> let C=A+B:

小数运算bc

  • 算数运算符

    1
    2
    3
    4
    5
    6
    7
    8
    [hadoop@hadoop01 ~]$ res= expr 2.3 + 3.5
    expr: non-integer argument
    [hadoop@hadoop01 ~]$ let res=2.3+3.5
    -bash: let: res=2.3+3.5: syntax error: invalid arithmetic operator (error token is ".3+3.5")
    [hadoop@hadoop01 ~]$ echo $[2.3+3.5]
    -bash: 2.3+3.5: syntax error: invalid arithmetic operator (error token is ".3+3.5")
    [hadoop@hadoop01 ~]$ echo $((2.3+3.5))
    -bash: 2.3+3.5: syntax error: invalid arithmetic operator (error token is ".3+3.5")
  • bc命令[hadoop@hadoop01 ~]$ sudo yum install -y bc

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    [hadoop@hadoop01 ~]$ echo "2.3+3.5"
    2.3+3.5
    # 浮点数运算
    [hadoop@hadoop01 ~]$ echo "2.3+3.5" | bc
    5.8
    # 比较运算: 非0为真(true 为1 ,false 为0)
    [hadoop@hadoop01 ~]$ echo "1<2" | bc
    1
    # 设置小数点位数: (3.33 保留二位小数)
    [hadoop@hadoop01 ~]$ echo "scale=2;10/3" | bc
    3.33
    # 设置进制: (将二进制111转为10进制 7)
    [hadoop@hadoop01 ~]$ echo "ibase=2;111" | bc
    7
    # 进制转换: (将10进制的10转为8进制 12)
    [hadoop@hadoop01 ~]$ echo "ibase=10;obase=8;10" | bc
    12
    # 高级运算:(计算3的3次幂)
    [hadoop@hadoop01 ~]$ echo "3^3" | bc
    27
    # (4的开方)
    [hadoop@hadoop01 ~]$ echo "sqrt(4)" | bc
    2

三元运算符

  • [ condition ] && 真 || 假 ,[ ]表达式内两侧必须有空格
1
2
3
4
5
6
7
8
#  1>=2 ? true : false
[hadoop@hadoop01 ~]$ [ 1 >= 2 ] && echo "true" || echo "false"
-bash: [: 1: unary operator expected
[hadoop@hadoop01 ~]$ [ 1 -gt 2 ] && echo "true" || echo "false"
false
# 1 >= 1 ? yes : no
[hadoop@hadoop01 ~]$ [ $(echo "3>2" | bc) -gt 1 ] && echo yes || echo no
no

关系运算符

运算符 等同运算符 说明
-eq = 检测二个数相等 ,相等返回true
-nq != 检测二个数不相等,不相等返回true
-ge >= 检测左边大于等于右边,是true
-gt > 检测左边大于右边,是true
-le <= 检测左边小于等于右边,是true
-lt < 检测左边小于右边,是true

布尔运算法

运算符 等同运算符 说明
-a && 与运算,二者为true,返回true
-o || 或运算,有一个表达式为true,则返回true;
! ! 非运算,表达式为true则返回false,否则返回true;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1>=2
[hadoop@hadoop01 ~]$ [ 1 -gt 2 ] && echo "true" || echo "false"
false
# !(1>=2)
[hadoop@hadoop01 ~]$ [ ! 1 -gt 2 ] && echo "true" || echo "false"
true
# (1>=2)&&(2=2)
[hadoop@hadoop01 ~]$ [ 1 -gt 2 -a 2 -eq 2 ] && echo "true" || echo "false"
false
# (1>=2) || (2=2)
[hadoop@hadoop01 ~]$ [ 1 -gt 2 -o 2 -eq 2 ] && echo "true" || echo "false"
true

[hadoop@hadoop01 ~]$ echo $((1>2 && 2>=2))
0
[hadoop@hadoop01 ~]$ echo $((1>2 || 2==2))
1
[hadoop@hadoop01 ~]$ echo $((1>2 || ! 2==2))
0
  • 脚本实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    #!/bin/bash
    ###本脚本主要写于20190905
    ###本脚本主要用于逻辑运算符
    if [ ! $1 ]
    then
    echo "==============该脚本运行格式: sh $0 变量1 变量2"
    break
    else
    if [ ! $2 ]
    then
    echo "==============该脚本运行格式: sh $0 变量1 变量2"
    break
    else
    echo "请输入你想要输入的数据:"
    read file
    ####获取输入的变量无法判断输入的类型,导致输入字符串类型会导致脚本报错
    ###非运算
    if [ $1 != $2 ]
    then
    echo "变量a不等于变量b"
    else
    echo "变量a等于变量b"
    fi
    ###与运算
    if [ $1 -lt $file -a $2 -gt $file ]
    then
    echo "变量a小于$file且变量b大于$file结果为真"
    else
    echo "变量a小于$file且变量b大于$file结果为假"
    fi

    ###或运算
    if [ $1 -lt $file -o $2 -gt $file ]
    then
    echo "变量a小于$file或者变量b大于$file结果为真"
    else
    echo "变量a小于$file或者变量b大于$file结果为假"
    fi
    fi
    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。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[hadoop@hadoop01 ~]$ str1='abc'
[hadoop@hadoop01 ~]$ str2='abcd'
[hadoop@hadoop01 ~]$ str3='bcde'
[hadoop@hadoop01 ~]$ str4=''
[hadoop@hadoop01 ~]$ [ $str1 = abc ] && echo yes || echo no
yes
[hadoop@hadoop01 ~]$ [ $str2 != abc ] && echo yes || echo no
yes
# -z 长度为0返回 true
[hadoop@hadoop01 ~]$ [ -z $str3 ] && echo "length is 0" || echo "length not 0"
length not 0
[hadoop@hadoop01 ~]$ [ -z $str4 ] && echo "length is 0" || echo "length not 0"
length is 0
# -n 不为0返回 true
[hadoop@hadoop01 ~]$ [ -n '' ] && echo "有值" || echo "空串"
空串
[hadoop@hadoop01 ~]$ [ -n "$str4" ] && echo "有值" || echo "空串"
空串
[hadoop@hadoop01 ~]$ [[ -n $str4 ]] && echo "有值" || echo "空串"
空串
[hadoop@hadoop01 ~]$ [ "$str4" ] && echo 存在str4 || echo 不存在str4
不存在str4
[hadoop@hadoop01 ~]$ str4='0'
[hadoop@hadoop01 ~]$ [ "$str4" ] && echo 存在str4 || echo 不存在str4
存在str4

[][[]]{},''""区别

引用的概念。所谓引用是指将字符串用某种符号括起来,以防止特殊字符被解析为其他意思。而在Shell中一共有4种引用符,分别是双引号单引号反引号转义符。双引号又叫“部分引用”或“弱引用”,可以引用除$符、反引号、转义符之外的所有字符;单引号又叫“全引用”或“强引用”,可以引用所有字符;反引号则会将反引号括起的内容解释为系统命令。

  • []:单中括号是比较基本的变量计算及数值比较的方法,一般情况下已经足够使用;

    • 单括号是对一段比较长的命令进行合并,单括号中的命令用-0或-a来进行衔接;
  • [[]]:双中括号是扩展的数值比较方法,里面的数值计算也相对来说复杂些。推荐大家平常工作中使用单中括号即可,满足日常的工作,不做运维开发的话,双括号方面涉及不多。

  • 双中括号就复杂多了,一半而言,涉及变量引用的话 ,双括号可以在数值计算中引用

  • 单引号与双引号的最大不同在于双引号仍然可以保有变量的内容,但单引号内仅能是一般字符 ,而不会有特殊符号。

    • 单引号比较笨一点,它不会将引号内的内容像变量一类的进行转换,举个例子:

      用echo显示变量:

      1
      2
      3
      4
      [hadoop@hadoop01 ~]$ echo "$JAVA_HOME"
      /usr/local/jdk1.8.0_211
      [hadoop@hadoop01 ~]$ echo '$JAVA_HOME'
      $JAVA_HOME
  • 双引号:部分引用是指用双引号括起来的引用,特殊字符会被解析为特殊意义,如上面的“JAVA_HOME”,

    • 打印该变量的时候,需要将它们用双引号括起来
  • 单引号: 全部引用是指用单引号括起来的引用。单引号中的任何字符都只当作是普通字符(除了单引号本身,也就是说单引号中间无法再包含单引号,即便用转义符转义单引号也不行)

    • 所有在单引号中的字符都只能代表其作为字符的字面意义

    • 全引用括起的字符串中还含有单引号会出现问题

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      # 因为Shell无法区分哪个单引号是引用的结束符,就像下面显示的一样:
      [root@localhost ~]# echo 'it's a dog'
      >

      # 解决这个问题,可以采取如下两种方式:
      # 1. 转义单引号
      [root@localhost ~]# echo 'it'\''s a dog'
      it's a dog
      # 2.使用双引号
      [root@localhost ~]# echo "it's a dog"
      it's a dog
  • 无引号:把内容输出出来,但可能不会将含有空格的字符串视为一个整体输出,

    • 如果内容中有命令,变量等,会先把变量,命令解析结果,然后再输出最终内容来,
    • 如果字符串中带有空格等特殊字符,则不能完整的输出,需要改加双引号
  • 花括号:

    • 以逗号分割的文件列表进行拓展,touch {a,b}.txt 结果为a.txt b.txt。

    • 对大括号中以点点(..)分割的顺序文件列表起拓展作用,如:touch {a..d}.txt 结果为a.txt b.txt c.txt d.txt

    • 代码块:大括号内的命令不会新开一个子shell运行,即脚本余下部分仍可使用括号内变量

      • 括号内的命令间用分号隔开,最后一个也必须有分号。

        1
        2
        3
        4
        ${var:-string}
        ${var:+string}
        ${var:=string}
        ${var:?string}

文件运算符

运算符 说明
-d 检测是否是目录,是true
-f 检测是否为普通文件,不是目录和设备文件,是true
-e 检测是否存在,是true
-s 检测文件是否不为空,(文件大小是否大于0),不为空true
-r 是否可读,是true
-w 是否可写,是true
-x 是否可执行,是true
-b 是否为块设备文件,是true
-c 是否是字符设备文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[hadoop@hadoop01 test]$ touch a.txt
[hadoop@hadoop01 test]$ ll
total 4
-rw-rw-r-- 1 hadoop hadoop 4 Aug 6 01:31 a.txt
# 检测是否是目录
[hadoop@hadoop01 test]$ [ -d "a.txt" ] && echo yes || echo no
no
# 检测是否为普通文件
[hadoop@hadoop01 test]$ [ -f "a.txt" ] && echo yes || echo no
yes
# 检测是否存在
[hadoop@hadoop01 test]$ [ -e "b.txt" ] && echo yes || echo no
no
# 检测是否不为空
[hadoop@hadoop01 test]$ [ -s "a.txt" ] && echo yes || echo no
no
# 检测是否不为空
[hadoop@hadoop01 test]$ echo aaa >> a.txt
[hadoop@hadoop01 test]$ [ -s "a.txt" ] && echo yes || echo no
yes
# 检测是否可读
[hadoop@hadoop01 test]$ [ -r "a.txt" ] && echo yes || echo no
yes
# 检测是否可写
[hadoop@hadoop01 test]$ [ -w "a.txt" ] && echo yes || echo no
yes
# 检测是否可执行
[hadoop@hadoop01 test]$ [ -x "a.txt" ] && echo yes || echo no
no
# 检测是否是块设备文件
[hadoop@hadoop01 test]$ [ -b "a.txt" ] && echo yes || echo no
no
# 检测是否是字符设备文件
[hadoop@hadoop01 test]$ [ -c "a.txt" ] && echo yes || echo no
no

流程控制语句

if

  • read -p 相当于Scanner,读取控制台的数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    if [condition];
    then
    语句1;
    elif[ condition ];
    then
    语句2;
    ...
    else
    语句3;
    fi
  • 例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #!/bin/bash
    read -p "请输入成绩:" SCORE
    if [ $SCORE -gt 80 ]
    then echo "优秀"
    elif [ $SCORE -gt 60 ]
    then echo "良好"
    else echo "一般般"
    fi

    [hadoop@hadoop01 test]$ . score.sh
    请输入成绩:61
    良好

case

1
2
3
4
5
6
7
8
9
10
case $1 in
值1)
语句1;
;;
值2)
语句二;
;;
*)
语句三
esac
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash
read -p "请输入成绩:" SCORE
SCORE=`expr $SCORE / 10 `
case $SCORE in
10)
echo "优秀"
;;
9)
echo "优秀"
;;
8)
echo "优秀"
;;
7)
echo "良好"
;;
6)
echo "一般"
;;
*)
echo "不及格"
esac

while

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
while [expression]/((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++
i=$((i+1))
done


--result:----------
1
2
3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash
i=1
result=0
while ((i<=100))
do
let result=result+i
let i++

done
echo $result

------------------------
#!/bin/bash
i=1
result=0
while [ $i -le 100 ]
do
let result=result+i
let i++

done
echo $result

for

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

  • 第一种:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    for 变量 in 列表
    do
    command
    ......
    done

    [hadoop@hadoop01 test]$ for N in 1 2 3;do echo $N ;done
    1
    2
    3
  • 第二种:

    1
    2
    3
    4
    [hadoop@hadoop01 test]$ for N in {1..3};do echo $N ; done
    1
    2
    3
  • 第三种

    1
    2
    3
    4
    [hadoop@hadoop01 test]$ for((i=0;i<=2;i++));do echo "welcome $i times"; done
    welcome 0 times
    welcome 1 times
    welcome 2 times
  • 例子

    1
    2
    3
    4
    5
    6
    7
    8
    //求一百的和
    #!/bin/bash
    result=0
    for((i=1;i<=100;i++))
    do
    let result=result+i
    done
    echo $result

until

  • expression 一般为条件表达式,如果返回false 则继续执行循环体,否则跳出循环,为true是跳出循环,和while相反
1
2
3
4
5
until expression((条件))/[]
do
command
......
done
1
2
3
4
5
6
7
8
9
#!/bin/bash
i=1;
sum=0;
until ((i>100))
do
let sum=sum+i
let i++
done
echo $sum

九九乘法表

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
for((i=1;i<=9;i++))
do
for((j=1;j<=i;j++))
do
echo -ne "$j * $i = `expr $i \* $j`\t"
# echo -ne "$j*$i=$[i*j]\t"
done
echo
done

数组

  • 使用小括号 ,数组内的元素用空格隔开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1. 数组的声明
arr=(aa bb cc)
2.获取某一个元素
echo ${arr[0]}
3.添加元素
arr[3]=dd
4.输出全部
echo ${arr[*]}
echo ${arr[@]}
5.获取数组的长度
echo ${#arr[*]}
6.获取数组的下标
echo ${!arr[*]}
7. 数组的连接(+=),下标接之间的最大值开始算
arr+=(dd ee ff)
echo ${arr[*]} #aa bb cc dd ee ff
8.删除数组
删除数组元素,会保留数组对应位置的下标unset ${arr[index]}
unset arr[0]
9.数组的分片
${arr[@]:number1:number2} 起始位置,取多少
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[hadoop@hadoop01 test]$ arr=(aa bb cc)
[hadoop@hadoop01 test]$ echo ${arr[@]}
aa bb cc
[hadoop@hadoop01 test]$ echo ${arr[0]}
aa
[hadoop@hadoop01 test]$ arr[3]=dd
[hadoop@hadoop01 test]$ echo ${arr[*]}
aa bb cc dd
# 长度
[hadoop@hadoop01 test]$ echo ${#arr[*]}
4
# 下标
[hadoop@hadoop01 test]$ echo ${!arr[*]}
0 1 2 3
[hadoop@hadoop01 test]$ arr+=(dd ee ff)
[hadoop@hadoop01 test]$ echo ${!arr[*]}
0 1 2 3 4 5 6
[hadoop@hadoop01 test]$ unset arr[5]
[hadoop@hadoop01 test]$ echo ${arr[*]}
aa bb cc dd dd ff
[hadoop@hadoop01 test]$ echo ${arr[*]:0:2}
aa bb
[hadoop@hadoop01 test]$ echo ${arr[@]:0:2}
aa bb
[hadoop@hadoop01 test]$ echo ${arr[@]:2:2}
cc dd

数组的遍历

  • 数组可能不是连续的,不能使用for(;;)的形式遍历
1
2
3
4
5
6
7
8
9
1. for元素循环遍历
for a in ${arr[*]};do echo $a ;done

2. 遍历下标
for a in ${!arr[*]};do echo ${arr[$a]} ;done
for a in ${!arr[*]};do echo ${arr[a]} ;done

2. 遍历值
for a in ${arr[*]};do echo $a ;done

函数

  • 一段代码块

  • 声明: 函数名(){command...}

  • 调用:函数名

  • 例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [hadoop@hadoop01 test]$ cat fun.sh
    #!/bin/bash
    hello(){
    echo "hahaha..."
    }
    # 调用函数
    hello
    #运行脚本
    [hadoop@hadoop01 test]$ sh fun.sh
    hahaha...

带参数和返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[hadoop@hadoop01 test]$ cat fun2.sh
#!/bin/bash
hello(){
name=$1
msg=$2
echo "$name在$msg"
}

echo "脚本传参:$*"
hello $1 $2

[hadoop@hadoop01 test]$ bash fun2.sh 张三 上海
脚本传参:张三 上海
张三在上海

跨脚本调用函数

1
2
3
4
5
6
7
8
9
10
11
12
[hadoop@hadoop01 test]$ cat other.sh
#!/bin/bash
. fun2.sh ## 引入脚本
hello $1 $2 ## 调用引入脚本当中的test函数
[hadoop@hadoop01 test]$ bash other.sh
脚本传参:


[hadoop@hadoop01 test]$ bash other.sh 武松 打大龙
脚本传参:武松 打大龙
武松在打大龙
武松在打大龙

集群自动安装软件

集群自动安装jdk

  1. 软件一致: httpd / yum
  2. 集群自动安装:
    • 一台机器自动安装(写脚本 autoInstall.sh)
    • 批量发送自动安装的脚本,自动执行脚本(send.sh)

准备:

  1. 传输文件到http服务器

    1
    2
    mkdir /var/www/html/jdk
    cp jdk-8u73-linux-x64.tar.gz /var/www/html/jdk/
  2. 编写自动下载安装的脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # autoInstall.sh
    #!/bin/bash
    #下载jdk
    wget http://192.168.2.101/jdk/jdk-8u73-linux-x64.tar.gz
    #解压jdk
    tar -zxvf jdk8.tar.gz -C /opt/
    #配置环境变量
    cat >> /etc/profile << EOF
    export JAVA_HOME=/opt/jdk8
    export PATH=$PATH:$JAVA_HOME/bin/
    EOF
    # 执行/etc/profile
    source /etc/profile
    # 测试
    java -version
  3. 自动配置免密

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    1.先安装expect
    yum -y install expect
    2.执行命令并匹配
    expect -c "
    spawn ssh-keygen
    expect {
    \"(/root/.ssh/id_rsa):\" {send \"\r\";exp_continue;}
    \"(empty for no passphrase):\" {send \"\r\";exp_continue;}
    \"passphrase again:\" {send \"\r\";exp_continue;}
    }
    "
    3.发送免密登录脚本
    expect -c "
    spawn ssh-copy-id ip
    expect {
    \"connecting (yes/no)?\" {send \"yes\r\";exp_continue;}
    \"password:\" {send \"centos\r\";exp_continue;}
    }
    "

    • 具体例子

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      #!/bin/bash
      # by liuxg
      # 2019.05.15
      # passwdless.sh


      # echo
      # -n 不要在最后自动换行
      # -e 处理特殊字符


      # expect是一个免费的编程工具语言,用来实现自动和交互式任务进行通信,而无需人的干预。
      # expect是不断发展的,随着时间的流逝,其功能越来越强大,已经成为系统管理员的的一个强大助手。
      # expect需要Tcl编程语言的支持,要在系统上运行expect必须首先安装Tcl。(源码安装要注意)

      yum install expect -y #安装expect
      echo "按enter键3次即可"

      # 生成秘钥(按enter键3次即可生成)
      ssh-keygen -t rsa

      SERVERS="172.18.74.167 172.18.74.169 172.18.74.172 172.18.74.173 172.18.74.174" #需要配置的主机名
      #SERVERS="m1 m2 m3 n1 n2"
      PASSWORD=123456 #需要配置的主机登录密码

      #将本机生成的公钥复制到其他机子上
      #如果(yes/no)则自动选择yes继续下一步
      #如果password:怎自动将PASSWORD写在后面继续下一步
      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 #遍历要发送到各个主机的ip
      do
      auto_ssh_copy_id $SERVER $PASSWORD
      done
      }
      ssh_copy_id_to_all

      passwordless.sh
  4. 发送安装和免密脚本并调用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # send.sh
    #!/bin/bash
    SERVICES=(192.168.2.101 192.168.2.102)
    for SERVICE in ${SERVICES[*]}
    do
    scp -r /root/autoInstall.sh root@$SERVICE:~/
    ssh root@$SERVICE sh autoInstall.sh
    echo "$SERVICE..."
    done

    #自动发送远程调用如果不能自动退出
    标准输入 0
    标准输出 1
    错误输出 2
    /dev/null "黑洞" 只写文件

    ssh root@$SERVICE > /dev/null 2>&1 <<EOF
    sh autoInstall.sh
    EOF

自动安装MySQL

安装mysql脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#!/bin/bash
## auto install mysql
## 假如是第二次装,那么要先停掉服务,并且卸载之前的mysql
service mysql stop
EXISTS_RPMS=`rpm -qa | grep -i mysql`
echo ${EXISTS_RPMS}
for RPM in ${EXISTS_RPMS}
do
rpm -e --nodeps ${RPM}
done

## 删除残留文件
rm -fr /usr/lib/mysql
rm -fr /usr/include/mysql
rm -f /etc/my.cnf
rm -fr /var/lib/mysql

## 从服务器获取安装mysql的rpm包
wget http://linux/soft/MySQL-client-5.6.26-1.linux_glibc2.5.x86_64.rpm
wget http://linux/soft/MySQL-server-5.6.26-1.linux_glibc2.5.x86_64.rpm

## 删除之前的密码文件,以免产生干扰
rm -rf /root/.mysql_secret

## 安装服务器
rpm -ivh MySQL-server-5.6.26-1.linux_glibc2.5.x86_64.rpm

## 获取到生成的随机密码
##PSWD=`cat /root/.mysql_secret | awk -F ':' '{print substr($4,2,16)}'`
PSWD=` grep -v '^$' /root/.mysql_secret | awk -F ':' '{print substr($4,2,16)}'`
##PSWD=${PWD:1:16}

## 安装客户端
rpm -ivh MySQL-client-5.6.26-1.linux_glibc2.5.x86_64.rpm

## 然后删除刚刚下下来的rpm包
rm -rf MySQL-client-5.6.26-1.linux_glibc2.5.x86_64.rpm
rm -rf MySQL-server-5.6.26-1.linux_glibc2.5.x86_64.rpm

## 提示安装的步骤都完成了。
echo "install mysql server and client is done .!!!!!!"

## 打印出来刚刚生成的mysql初始密码
echo "random password is:${PSWD}"

## 开启mysql服务
service mysql start
  • 手动第一次登陆,然后改掉密码

    1
    2
    [root@hadoop bin]# mysql -uroot -pZjVIWvOGD18bT7oX
    mysql> set PASSWORD=PASSWORD('root');
  • 现在就可以写脚本链接mysql进行操作了

    1
    2
    3
    4
    5
    6
    7
    8
    [root@hadoop bin]# vi initMysql.sh
    #!/bin/bash
    mysql -uroot -proot << EOF
    GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;
    FLUSH PRIVILEGES;
    use mysql;
    select host, user, password from user;
    EOF