Linux-Shell

Linux-Shell

第 1 章 Shell 概述

  • Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。

  • Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。

  • Shell 脚本(shell script),是一种为 shell 编写的脚本程序。

  • Shell 编程跟 JavaScript、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。

Linux 的 Shell 种类众多,常见的有:

Bourne Shell(/usr/bin/sh或/bin/sh)
Bourne Again Shell(/bin/bash)
C Shell(/usr/bin/csh)
K Shell(/usr/bin/ksh)
Shell for Root(/sbin/sh)

sh/bash/csh/Tcsh/ksh/pdksh等shell的区别:

  • sh(全称 Bourne Shell): 是UNIX最初使用的 shell,而且在每种 UNIX 上都可以使用。

  • Bourne Shell: 在 shell 编程方面相当优秀,但在处理与用户的交互方面做得不如其他几种 shell。

  • bash(全称 Bourne Again Shell): LinuxOS 默认的,它是 Bourne Shell 的扩展。 与 Bourne Shell 完全兼容,并且在 Bourne Shell 的基础上增加了很多特性。可以提供命令补全,命令编辑和命令历史等功能。它还包含了很多 C Shell 和 Korn Shell 中的优点,有灵活和强大的编辑接口,同时又很友好的用户界面。

  • csh(全称 C Shell): 是一种比 Bourne Shell更适合的变种 Shell,它的语法与 C 语言很相似。

  • Tcsh: 是 Linux 提供的 C Shell 的一个扩展版本。Tcsh 包括命令行编辑,可编程单词补全,拼写校正,历史命令替换,作业控制和类似 C 语言的语法,他不仅和 Bash Shell 提示符兼容,而且还提供比 Bash Shell 更多的提示符参数。

  • ksh(全称 Korn Shell): 集合了 C Shell 和 Bourne Shell 的优点并且和 Bourne Shell 完全兼容。

  • pdksh: 是 Linux 系统提供的 ksh 的扩展。pdksh 支持人物控制,可以在命令行上挂起,后台执行,唤醒或终止程序。

  1. Linux 提供的 Shell 解析器有
[root@myvm ~]# cat /etc/shells 
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/bin/tcsh
/bin/csh
  1. bash 和 sh 的关系

    [root@myvm ~]# ls -l /bin/ | grep bash
    -rwxr-xr-x. 1 root root     964536 41 2020 bash
    lrwxrwxrwx. 1 root root         10 818 13:47 bashbug -> bashbug-64
    -rwxr-xr-x. 1 root root       6964 41 2020 bashbug-64
    lrwxrwxrwx. 1 root root          4 818 13:47 sh -> bash
    
  2. Centos 默认的解析器是 bash

    [root@myvm ~]# echo $SHELL
    /bin/bash
    

第 2 章 Shell 脚本入门

  1. 脚本格式

    脚本以 #!/bin/bash 开头(指定解析器)

    #! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序。

  2. 第一个 Shell 脚本:hello.sh

    打开文本编辑器(可以使用 vi/vim 命令来创建文件),新建一个文件 helloworld.sh,扩展名为 sh(sh代表shell),扩展名并不影响脚本执行。

    [root@myvm]# touch helloworld.sh
    [root@myvm]# vim helloworld.sh
    
    // 在 helloworld.sh 中输入如下内容
    
    #!/bin/bash
    echo "helloworld"
    
  3. 脚本的常用执行方式

    • bash / sh + 相对路径/绝对路径(不用赋予脚本+x 权限)

      • 这种执行方法,本质是 bash 解析器帮你执行脚本,所以脚本本身不需要执权限。
      [root@myvm ~]# bash scripts/hello.sh 
      hello world
      [root@myvm ~]# bash /root/scripts/hello.sh 
      hello world
      
    • 采用输入脚本的 绝对路径 或 相对路径 执行脚本 (必须具有可执行权限+x)

      • 这种执行方法,本质是脚本需要 自己 执行,所以需要执行权限。
      [root@myvm ~]# chmod a+x scripts/hello.sh
      [root@myvm ~]# /root/scripts/hello.sh 
      hello world
      [root@myvm ~]# scripts/hello.sh 
      hello world
      
    • 在脚本的路径前加上“.”或者 source

      [root@myvm scripts]# source hello.sh 
      hello world
      [root@myvm scripts]# . hello.sh 
      hello world
      
  • 前两种方式都是在当前 shell 中打开一个子 shell来执行脚本内容,当脚本内容结束,则 子 shell 关闭,回到父 shell 中。
  • 第三种,也就是使用在脚本路径前加“.”或者 source 的方式,可以使脚本内容在当前 shell 里执行,而无需打开子 shell!这也是为什么我们每次要修改完/etc/profile 文件以后,需要 source 一下的原因。
  • 开子 shell 与不开子 shell 的区别就在于,环境变量的继承关系,如在子 shell 中设置的 当前变量,父 shell 是不可见的

Shell 注释

以 # 开头的行就是注释,会被解释器忽略,通过每一行加一个 # 号设置多行注释。

# 这是一个注释

##### 开始 #####

#
#

# 这里可以添加描述信息

#
#

##### 结束  #####


多行注释还可以使用以下格式

:<<EOF
注释内容...
注释内容...
注释内容...
EOF

EOF 也可以使用其他符号

:<<'
注释内容...
注释内容...
注释内容...
'

:<<!
注释内容...
注释内容...
注释内容...
!

第 3 章 变量

3.1 系统预定义变量

  1. 常用系统变量 $HOME $PWD $SHELL $USER
    • 查看系统变量的值echo $HOME
    • 显示当前 Shell 中所有变量(系统和用户定义的所有全局变量, 局部变量):set
    • 显示 系统 定义的全局变量 env
    • 打印系统环境变量 printenv HOME

3.2 自定义变量

1.基本语法

  • 定义变量:变量名=变量值,注意,=号前后不能有空格

  • 撤销变量:unset 变量名

  • 声明静态变量(只读变量):readonly 变量,注意:不能对只读变量进行 unset

  • 可把变量提升为全局环境变量,可供其他 Shell 程序使用: export 变量名

2.变量定义规则

  • 变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建议大写。
  • 中间不能有空格,可以使用下划线
  • 变量的值如果有空格,需要使用双引号或单引号括起来。
  • 等号两侧不能有空格
  • 不能使用bash里的关键字(可用help命令查看保留关键字)
  • 在 bash 中,变量默认类型都是字符串类型,无法直接进行数值运算。

3.变量类型:运行shell时,会同时存在三种变量:

  • 局部变量: 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。

  • 环境变量: 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。

  • shell变量: shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行。

参考实例

[root@myvm scripts]# vim hello.sh 
---- vim中的内容 ----
#!/bin/bash
echo "hello world"
echo $my_var # 已经存在的全局变量
echo $new_var # 普通变量
--------------------          

[root@myvm scripts]# ./hello.sh 
hello world
hello, world
				# 使用新的子bash, 局部变量未输出
[root@myvm scripts]# . hello.sh 
hello world
hello, world
hello, Linux  # 在当前bash, 局部变量输出
[root@myvm scripts]# export new_var ---> 设置为全局变量
[root@myvm scripts]# ./hello.sh 
hello world
hello, world
hello, Linux  # 全局变量在子bash中输出
[root@myvm scripts]# echo $a
2

# 直接对变量进行运算赋值, 视为字符串
[root@myvm scripts]# a=1+5
[root@myvm scripts]# echo $a
1+5

# 对变量进行运算结果的赋值, $(()) 或 $[]
[root@myvm scripts]# a=$((1+5))
[root@myvm scripts]# echo $a
6
[root@myvm scripts]# a=$[5+9]
[root@myvm scripts]# echo $a
14

# 定义只读变量
[root@myvm scripts]# readonly b=5
[root@myvm scripts]# b=10
-bash: b: 只读变量
[root@myvm scripts]# echo $b
5

直接执行命令: 将脚本放入root/bin 或 将脚本的路径放入环境变量

3.3 特殊变量

$n
  1. 基本语法

    $n (功能描述:n 为数字,$0 代表该脚本名称,$1-$9 代表第一到第九个参数,十以 上的参数,十以上的参数需要用大括号包含,如${10}

  2. 参考实例

    [root@myvm scripts]# touch parameter.sh
    [root@myvm scripts]# vim parameter.sh
    #!/bin/bash
    echo '========$n======='
    echo script name: $0
    echo 1st parameter: $1
    echo 2nd parameter: $2
    
    [root@myvm scripts]# chmod +x parameter.sh
    [root@myvm scripts]# ./parameter.sh 123 456
    ========$n=======
    script name: ./parameter.sh
    1st parameter: 123
    2nd parameter: 456
    
$#
  1. 基本语法

    $# (功能描述:获取所有输入参数个数,常用于循环,判断参数的个数是否正确以及 加强脚本的健壮性)

  2. 参考实例

    #!/bin/bash
    echo '========$n======='
    echo script name: $0
    echo 1st parameter: $1
    echo 2nd parameter: $2
    echo '========$#======='
    echo parameter number: $#
    
    [root@myvm scripts]# ./parameter.sh 123 456
    ========$n=======
    script name: ./parameter.sh
    1st parameter: 123
    2nd parameter: 456
    ========$#=======
    parameter number: 2
    
$*$@
  1. 基本语法

    $* (功能描述:这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体

    $@ (功能描述:这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待

  2. 参考实例

    #!/bin/bash
    echo '========$n======='
    echo script name: $0
    echo 1st parameter: $1
    echo 2nd parameter: $2
    echo '========$#======='
    echo parameter number: $#
    echo '========$*======='
    echo $*
    echo '========$@======='
    echo $@
    
    [root@myvm scripts]# ./parameter.sh 123 456
    ========$n=======
    script name: ./parameter.sh
    1st parameter: 123
    2nd parameter: 456
    ========$#=======
    parameter number: 2
    ========$*=======
    123 456
    ========$@=======
    123 456
    
  3. 比较$*$@区别

[root@myvm ~]# vim parameter_for_test.sh
#!/bin/bash

echo '-------$*--------' # 要显示$符就要用'',""会将$解析
for para in "$*" # 若 $* 和 $@ 不加"", 则二者没有区别, 输出都是第二种形式(将所有的参数分开)
do
        echo $para
done

echo '-------$@--------' # 要显示$符就要用'',""会将$解析
for para in "$@"
do
        echo $para
done


=======================================================================
[root@myvm ~]# ./parameter_for_test.sh a b c d e
-------$*--------
a b c d e
-------$@--------
a
b
c
d
e
$?
  1. 基本语法

    $? (功能描述:最后一次执行的命令的返回状态。如果这个变量的值为 0,证明上一 个命令正确执行;如果这个变量的值为非 0(具体是哪个数,由命令自己来决定),则证明 上一个命令执行不正确了。)

  2. 参考实例

    判断 helloworld.sh 脚本是否正确执行

    [root@myvm scripts]# ./hello.sh 
    hello world 
    [root@myvm scripts]# echo $?
    0
    

第 4 章 运算符

  1. 基本语法

    • $((运算式))$[运算式]

      • 该方式中的运算式之间空格随意

      • $(()) 中间可以直接跟一个数学运算式, 不需要 -lt 等

        • [root@myvm bin]# echo $[5 * 2]
          10
          [root@myvm bin]# echo $[5*2]
          10
          [root@myvm bin]# echo $[5* 2]
          10
          [root@myvm bin]# echo $((5*2))
          10
          
      • 赋值

        • [root@myvm bin]# a=$[6+8]
          [root@myvm bin]# echo $a
          14
          [root@myvm bin]# s=$[(2+3) * 4]
          [root@myvm bin]# echo $s
          20
          
    • expr 参数1 运算符 参数2

    • 乘号需要进行转义: expr 5 \* 2

    • 必须有表达式上的空格

    • 赋值(可用 反引号 替代$() )

      • [root@myvm bin]# a=$(expr 5 \* 2)
        [root@myvm bin]# echo $a
        10
        [root@myvm bin]# a=`expr 5 \* 4`
        [root@myvm bin]# echo $a
        20
        
  2. 参考实例

    [root@myvm scripts]# vim add.sh
    #!/bin/bash
    sum=$[$1 + $2]
    echo sum=$sum
    
    [root@myvm scripts]# chmod +x add.sh 
    [root@myvm scripts]# ./add.sh 25 89
    sum=114
    

第 5 章 条件判断

  1. 基本语法

    (1)test condition (要分开, 否则视为一个字符串 eg: $a = hello)

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

    注意:条件非空即为 true,[ abc ] 返回 true,[ ] 返回 false

  2. 常用判断条件

    (1)两个整数之间比较

    • -eq 等于(equal)

    • -ne 不等于(not equal)或 !=

    • -lt 小于(less than)

    • -le 小于等于(less equal)

    • -gt 大于(greater than)

    • -ge 大于等于(greater equal)

    注:如果是字符串之间的比较 ,用等号“=”判断相等;用“!=”判断不等。

    (2)按照文件权限进行判断

    • -r 有读的权限(read)

    • -w 有写的权限(write)

    • -x 有执行的权限(execute)

    (3)按照文件类型进行判断

    • -e 文件存在(existence)

    • -f 文件存在并且是一个常规的文件(file)

    • -d 文件存在并且是一个目录(directory)

    (4)多条件判断

    • && 表示前一条命令执行成功时,才执行后一条命令
    • || 表示上一条命令执行失败后,才执行下一条命令
  3. 参考实例

    # -----------使用test----------
    [root@myvm scripts]# a=Hello
    # 视为一个字符串, 此时返回0
    [root@myvm scripts]# test $a=hello
    [root@myvm scripts]# echo $?
    0
    [root@myvm scripts]# test $a = Hello
    [root@myvm scripts]# echo $?
    0
    [root@myvm scripts]# test $a = hello
    [root@myvm scripts]# echo $?
    1
    
    # --------使用[ ]---------
    # 没有空格, 视为命令
    [root@myvm scripts]# [$a = Hello]
    bash: [Hello: 未找到命令...
    [root@myvm scripts]# [ $a = Hello ]
    [root@myvm scripts]# echo $?
    0
    [root@myvm scripts]# [ $a = hello ]
    [root@myvm scripts]# echo $?
    1
    # 任意的非空字符串, 判断为true
    [root@myvm scripts]# [ adsdasdsad ]
    [root@myvm scripts]# echo $?
    0
    # 空字符串, 判断为false
    [root@myvm scripts]# [ ]
    [root@myvm scripts]# echo $?
    1
    # 没有空格, 视为命令
    [root@myvm scripts]# []
    bash: []: 未找到命令...
    
    # -------- != ---------
    [root@myvm scripts]# [ $a != Hello ]
    [root@myvm scripts]# echo $?
    1
    [root@myvm scripts]# [ $a != hello ]
    [root@myvm scripts]# echo $?
    0
    
    # -------- > = < ---------
    [root@myvm ~]# a=3
    [root@myvm ~]# if (( $a > 2 )); then echo OK; else echo notOK; fi
    OK
    [root@myvm scripts]# [ 2 -lt 8 ]
    [root@myvm scripts]# echo $?
    0
    [root@myvm scripts]# [ 2 -gt 8 ]
    [root@myvm scripts]# echo $?
    1
    
    # --------- -r -w -x ----------
    [root@myvm scripts]# ll
    总用量 12
    -rwxr-xr-x. 1 root root  41 93 15:07 add.sh
    -rwxr-xr-x. 1 root root  47 92 23:07 hello.sh
    -rwxr-xr-x. 1 root root 221 92 23:17 parameter.sh
    -rw-r--r--. 1 root root   0 93 16:07 test
    [root@myvm scripts]# [ -r hello.sh ]
    [root@myvm scripts]# echo $?
    0
    [root@myvm scripts]# [ -r test ]
    [root@myvm scripts]# echo $?
    0
    [root@myvm scripts]# [ -x test ]
    [root@myvm scripts]# echo $?
    1
    
    # --------- -e -f -d ----------
    [root@myvm scripts]# [ -e /home/kiddkid/info ]
    [root@myvm scripts]# echo $?
    1
    [root@myvm scripts]# [ -f add.sh ]
    [root@myvm scripts]# echo $?
    0
    [root@myvm scripts]# [ -d add.sh ]
    [root@myvm scripts]# echo $?
    1
    [root@myvm scripts]# [ -d /home/kiddkid ]
    [root@myvm scripts]# echo $?
    0
    
    # --------- && || 实现 三目运算符的功能 ----------
    [root@myvm scripts]# a=15
    [root@myvm scripts]# [ $a -lt 20 ] && echo "$a < 20" || echo "$a >=2
    15 < 20
    [root@myvm scripts]# a=27
    [root@myvm scripts]# [ $a -lt 20 ] && echo "$a < 20" || echo "$a >=2
    27 >=20 
    [root@myvm scripts]# [ kiddkid ] && echo OK || echo notOK
    OK
    [root@myvm scripts]# [ ] && echo OK || echo notOK
    notOK
    

第 6 章 流程控制

if 判断

  1. 基本语法

(1)单分支

if [ 条件判断式 ];then 
	程序 
fi 

或者

if [ 条件判断式 ] 
then 
	程序 
fi 

(2)多分支

if [ 条件判断式 ] 
then 
	程序 
elif [ 条件判断式 ] 
then 
	程序 
else 
	程序 
fi

注意事项:

①[ 条件判断式 ],中括号和条件判断式之间必须有空格

②if 后要有空格

  1. 参考实例

    (1) 行内判断

    分号表示两个命令之间的分隔符, 按照从左到右的顺序执行

    [root@myvm ~]# a=25
    [root@myvm ~]# if [ $a -gt 18 ]; then echo OK; fi
    OK
    [root@myvm ~]# a=15
    [root@myvm ~]# if [ $a -gt 18 ]; then echo OK; fi
    
    # 使用逻辑与进行判断
    [root@myvm scripts]# a=25
    [root@myvm scripts]# if [ $a -gt 18 ] && [ $a -lt 35 ]; then echo OK;fi
    OK
    # 在if中只写一个中括号 则需要用 -a: all, 表示&& ; -o: or, 表示||
    [root@myvm scripts]# if [ $a -gt 18 -a $a -lt 35 ]; then echo OK;fi 
    [root@myvm scripts]# a=20
    [root@myvm scripts]# if [ $a -gt 18 -a $a -lt 35 ]; then echo OK;fiOK
    

    (2) 脚本判断

    #!/bin/bash
    if [ "$1"x = "kiddkid"x ]  # ( 加一x,防止参数为空时报错)
    then
            echo "welcome, kiddkid"
    fi
    
    # 输入第二个参数, 表示年龄, 判断属于哪个年龄段
    :<<!
    if [ $2 -lt 18 ]
    then 
            echo "未成年人"
    else
            echo "成年人"
    fi
    !
    
    if [ $2 -lt 18 ]
    then
            echo "未成年人"
    elif [ $2 -lt 35 ]
    then
            echo "青年人"
    elif [ $2 -lt 60 ]
    then
            echo "中年人"
    else
            echo "老年人"
    fi
    
    # -------- 测试 ---------
    [root@myvm scripts]# ./if_test.sh kiddkid 15
    welcome, kiddkid
    未成年人
    [root@myvm scripts]# ./if_test.sh kiddkid 25
    welcome, kiddkid
    青年人
    [root@myvm scripts]# ./if_test.sh kiddkid 36
    welcome, kiddkid
    中年人
    [root@myvm scripts]# ./if_test.sh kiddkid 67
    welcome, kiddkid
    老年人
    

case 语句

  1. 基本语法

    case $变量名 in
    "值 1"# 可以不加引号
    如果变量的值等于值 1,则执行程序 1
    ;;
    "值 2")
    如果变量的值等于值 2,则执行程序 2
    ;;
    …省略其他分支…
    *)
    如果变量的值都不是以上的值,则执行此程序
    ;;
    esac
    

    注意事项:

    (1)case 行尾必须为单词“in”,每一个模式匹配必须以右括号“)”结束。

    (2)双分号“;;”表示命令序列结束,相当于 java 中的 break。

    (3)最后的“*)”表示默认模式,相当于 java 中的 default。

  2. 参考实例

    #!/bin/bash
    
    case $1 in
    1)
            echo "one"
    ;;
    2)
            echo "two"
    ;;
    3)
            echo "three"
    ;;
    *)
            echo "number else"
    ;;
    esac
    
    
    [root@myvm ~]# ./case_test.sh 2
    two
    [root@myvm ~]# ./case_test.sh 1
    one
    [root@myvm ~]# ./case_test.sh 5
    number else
    

for 循环

  1. 基本语法1

    在 (( )) 中可直接写数学符号, 不需要写 -lt 等

    for (( 初始值;循环控制条件;变量变化 ))
    do
    程序
    done
    
    • 参考实例

      [root@myvm scripts]# vim sum_to.sh
      
      #!/bin/bash
      
      for (( i=1; i <= $1;i++ ))
      do
              sum=$[ $sum + $i ]
      done
      
      echo $sum
      
      [root@myvm scripts]# ./sum_to.sh 100
      5050
      

    2.基本语法2

    for 变量 in123do
    程序
    done
    
    • 参考实例

      [root@myvm scripts]# for os in linux windows macos; do echo $os; done
      linux
      windows
      macos
      
      [root@myvm scripts]# for i in {1..100}; do sum=$[$sum + $i]; done;echo $sum
      5050
      # {}中间的值与花括号之间不能有空格, 否则报错{: 语法错误: 期待操作数 (错误符号是 "{")
      

while 循环

  1. 基本语法

    while [ 条件判断式 ]
    do
    程序
    done
    
  2. 参考实例

    [root@myvm ~]# vim sum_to.sh 
    
    a=1
    while [ $a -le $1 ]
    do
    
    # 第一种方式(正式)
    #       sum2=$[ $sum2 + $a ]
    #       a=$[ $a + 1 ]
    
    # 第二种方式
            let sum2+=a
            let a++
    done
    
    echo $sum2
    
    [root@myvm ~]# ./sum_to.sh 100
    5050
    

第 7 章 read 读取控制台输入

  1. 基本语法

    read (选项) (参数)

    ①选项:

    -p:指定读取值时的提示符;

    -t:指定读取值时等待的时间(到达规定时间后自动结束)(秒)如果-t 不加表示一直等待

    ②参数

    ​ 变量:指定读取值的变量名

  2. 参考实例

    [root@myvm ~]# vim read_test.sh
    [root@myvm ~]# chmod +x read_test.sh 
    
    #!/bin/bash
    
    read -t 10 -p "请输入您的芳名: " name
    echo "welcome, $name" 
    
    [root@myvm ~]# ./read_test.sh 
    请输入您的芳名: kiddkid
    welcome, kiddkid
    

第 8 章 函数

8.1 系统函数

8.1.1 basename
  1. 基本语法

    basename [string / pathname] [suffix]

    • 功能描述:

      • basename 命令会删掉所有的 前缀 包括最后一个(‘/’)字符,然后将字符串显示出来

      • basename 可以理解为取路径里的文件名称

    • 选项: suffix 为后缀,如果 suffix 被指定了,basename 会将 pathname 或 string 中的 suffix 去掉

  2. 参考实例

    # 取文件名, 带后缀
    [root@myvm scripts]# basename /root/scripts/paramater.sh
    paramater.sh
    
    # 取文件名, 不带后缀
    [root@myvm scripts]# basename /root/scripts/paramater.sh .sh
    paramater
    
8.1.2 dirname
  1. 基本语法

    dirname 文件绝对路径

    • 功能描述

      • 从给定的包含绝对路径的文件名中 去除文件名 (非目录的部分),然后返回剩下的路径(目录的部分)

      • dirname 可以理解为取文件路径的绝对路径名称

  2. 参考实例

    [root@myvm scripts]# dirname /root/scripts/parameter.sh
    /root/scripts
    
    # 在脚本中 取文件的绝对路径
    #!/bin/bash
    echo '========$n======='
    echo script name: $(basename $0 .sh)
    echo script path: $(cd $(dirname $0); pwd) # 先cd到目标目录, 再pwd输出绝对路径
    echo 1st parameter: $1
    echo 2nd parameter: $2
    echo '========$#======='
    echo parameter number: $#
    echo '========$*======='
    echo $*
    echo '========$@======='
    echo $@
    
    [root@myvm scripts]# cd /home/kiddkid/
    [root@myvm kiddkid]# ../../root/scripts/parameter.sh a b
    ========$n=======
    script name: parameter
    script path: /root/scripts
    1st parameter: a
    2nd parameter: b
    ========$#=======
    parameter number: 2
    ========$*=======
    a b
    ========$@=======
    a b
    

8.2 自定义函数

  1. 基本语法 ( 带[]的地方意味着 [] 里的内容可以省略 )

    [ function ] funname[()]
    {
    Action;
    [return int;]
    }
    
  2. 经验技巧

    (1)必须在调用函数地方之前,先声明函数,shell 脚本是逐行运行。不会像其它语言一 样先编译。

    (2)函数返回值,只能通过$?系统变量获得,可以显示加:return 返回,如果不加,将以 最后一条命令运行结果 作为返回值。return 后跟数值 n(0-255)

  3. 参考实例

    [root@myvm scripts]# vim fun_test.sh 
    [root@myvm scripts]# chmod +x fun_test.sh 
    
    #!/bin/bash
    
    function add() {
            s=$[$1 + $2]
            echo $s
    }
    
    read -p "请输入第一个整数: " a
    read -p "请输入第二个整数: " b
    
    sum=$(add $a $b) # 此处使用了函数的返回值
    echo "和: "$sum
    echo "和的平方: "$[$sum * $sum]
    
    [root@myvm scripts]# ./fun_test.sh 156 237
    请输入第一个整数: 156
    请输入第二个整数: 237
    和: 393
    和的平方: 154449
    

本章应用

设定一个定时任务, 将 /root/scripts 下的文件按照 一定的文件名 定时归档

[root@myvm scripts]# vim daily_archive.sh 

#!/bin/bash

# 首先判断 输入参数个数 是否为1
if [ $# -ne 1 ]
then
        echo "参数个数错误! 应该输入一个参数, 作为归档目录名"
        exit
fi

# 从参数中获取目录名称
if [ -d $1 ]
then
        echo
else
        echo
        echo "目录不存在!"
        echo
        exit
fi

DIR_NAME=$( basename $1 )
DIR_PATH=$(cd $(dirname $1); pwd)

# 获取当前日期
DATE=$(date +%y%m%d)

# 定义生成的归档文件的名称
FILE=archive_${DIR_NAME}_$DATE.tar.gz
DEST=/root/archive/$FILE


# 开始归档目录文件

echo "开始归档..."
echo

tar -czf $DEST $DIR_PATH/$DIR_NAME

if [ $? -eq 0 ]
then
        echo
        echo "归档成功!"
        echo "归档文件为: $DEST"
        echo
else
        echo "归档出现问题!"
        echo
fi

exit

[root@myvm scripts]# crontab -l
no crontab for root
[root@myvm scripts]# crontab -e
crontab: installing new crontab
[root@myvm scripts]# crontab -l
0 2 * * * /root/scripts/daily_archive.sh /root/scripts

第 9 章 正则表达式入门

在 Linux 中,grep, sed,awk 等文本处理工具都支持通过正则表达式进行模式匹配

9.1 常规匹配

一串不包含特殊字符的正则表达式匹配它自己

[root@myvm scripts]# cat /etc/passwd | grep kiddkid
kiddkid:x:1000:1000:kiddkid:/home/kiddkid:/bin/bash

9.2 常用特殊字符

  1. 特殊字符

    特殊字符功能
    ^匹配一行的开头
    $匹配一行的结尾
    .匹配一个任意的字符
    *不单独使用,他和上一个字符连用,表示匹配上一个字符 0 次或多次
    [ ]表示匹配某个范围内的一个字符
    \\ 表示转义,并不会单独使用
  • 延伸:

    • [6,8]------匹配 6 或者 8

    • [0-9]------匹配一个 0-9 的数字

    • [0-9]*------匹配任意长度的数字字符串

    • [a-z]------匹配一个 a-z 之间的字符

    • [a-z]* ------匹配任意长度的字母字符串

    • [a-c, e-f]-匹配 a-c 或者 e-f 之间的任意字符

  1. 参考实例
  • ^ $
[root@myvm scripts]# cat /etc/passwd | grep ^k
kiddkid:x:1000:1000:kiddkid:/home/kiddkid:/bin/bash

[root@myvm scripts]# cat /etc/passwd | grep bash$
root:x:0:0:root:/root:/bin/bash
kiddkid:x:1000:1000:kiddkid:/home/kiddkid:/bin/bash
tony:x:1001:1003::/home/tony:/bin/bash
david:x:1002:1003::/home/dave:/bin/bash
xiaoming:x:1003:1004::/home/xiaoming:/bin/bash
xiaohong:x:1004:1005::/home/xiaohong:/bin/bash
xiaolan:x:1005:1004::/home/xiaolan:/bin/bash
xiaoliang:x:1006:1004::/home/xiaoliang:/bin/bash
mysql:x:987:1006::/home/mysql:/bin/bash

[root@myvm scripts]# cat /etc/passwd | grep ^kbash$
# 开头到结尾之间必须是kbash

[root@myvm scripts]# cat daily_archive.sh | grep -n ^$
2:
9:
20:
23:
26:
30:
31:
33:
36:
38:
49:
51:
52:
  • . *
[root@myvm scripts]# cat /etc/passwd | grep r..t
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

[root@myvm scripts]# cat /etc/passwd | grep ro*t
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin

[root@myvm scripts]# cat /etc/passwd | grep ^a.*in$
adm:x:3:4:adm:/var/adm:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
  • [ ] \
[root@myvm scripts]# echo "rbababtfjefoe" | grep r[a-z]*t
rbababtfjefoe

[root@myvm scripts]# cat daily_archive.sh | grep '/\$'
DEST=/root/archive/$FILE
tar -czf $DEST $DIR_PATH/$DIR_NAME
  1. 综合应用: 判断手机号
[root@myvm scripts]# echo "13812345678" | grep -E ^1[34578][0-9]{9}$
13812345678

第 10 章 文本处理工具

10.1 cut

常用于分割列

cut 的工作就是“剪”,具体的说就是在文件中负责剪切数据用的。cut 命令从文件的每 一行剪切字节、字符和字段并将这些字节、字符和字段输出。

  1. 基本用法

    cut [选项参数] filename

    说明:默认分隔符是制表符

  2. 选项参数说明

    选项参数功能
    -f列号,提取第几列
    -d分隔符,按照指定分隔符分割列,默认是制表符“\t”
    -c按 字符 进行切割 后加 n 表示取第几列 比如 -c 1
  3. 参考实例

    [root@myvm scripts]# vim cut.txt
    [root@myvm scripts]# cat cut.txt 
    dong shen
    guan zhen
    wo wo
    lai lai
    le le
    
    # 查找第1列
    [root@myvm scripts]# cut -d " " -f 1 cut.txt 
    dong
    guan
    wo
    lai
    le
    
    # 第2,3(不存在)列
    [root@myvm scripts]# cut -d " " -f 2,3 cut.txt 
    shen
    zhen
    wo
    lai
    le
    
    # 第7列
    [root@myvm scripts]# cat /etc/passwd | grep bash$ | cut -d ":"7
    
    # 1-4列
    [root@myvm scripts]# cat /etc/passwd | grep bash$ | cut -d ":" -f 1-4
    
    # 从第4列到最后一列
    [root@myvm scripts]# cat /etc/passwd | grep bash$ | cut -d ":" -f 4-
    
    # 从第一列到最后一列
    [root@myvm scripts]# cat /etc/passwd | grep bash$ | cut -d ":" -f 1-
    

10.2 awk

一个强大的文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开 的部分再进行分析处理。

  1. 基本用法

    awk [选项参数] ‘/pattern1/{action1} /pattern2/{action2}...’ filename

    • pattern:表示 awk 在数据中查找的内容,就是匹配模式

    • action:在找到匹配内容时所执行的一系列命令

  2. 选项参数说明

选项参数功能
-F指定输入文件分隔符
-v赋值一个用户定义变量
  1. awk 的内置变量
变量说明
FILENAME文件名
NR已读的记录数 (行号)
NF浏览记录的域的个数(切割后,列的个数)
  1. 参考实例
[root@myvm scripts]# cat /etc/passwd | awk -F ":" '/^root/ {print $7}' 
/bin/bash
[root@myvm scripts]# cat /etc/passwd | awk -F ":" '/^root/ {print $1",4"$7}'
root,4/bin/bash
[root@myvm scripts]# cat /etc/passwd | awk -F ":" '/^root/ {print $1","$6","$7}'
root,/root,/bin/bash
[root@myvm scripts]# cat /etc/passwd | awk -F ":" '/^root/ {print $1,$6","$7}'
root /root,/bin/bash

  • BEGIN 在所有数据读取行之前执行;END 在所有数据执行之后执行。

    [root@myvm scripts]# cat /etc/passwd | awk -F ":" 'BEGIN{print "user,shell"} {print $1","$7} END{print "end of file"}'
    user,shell
    root,/bin/bash
    bin,/sbin/nologin
    daemon,/sbin/nologin
    ...
    end of file
    
    
  • 将 passwd 文件中的用户id增加数值1并输出

    [root@myvm scripts]# cat /etc/passwd | awk -F ":" '{print $3 + 1}'
    1
    2
    3
    4
    ...
    
    [root@myvm scripts]# cat /etc/passwd | awk -v i=1 -F ":" '{print $3 + i}'
    1
    2
    3
    4
    ...
    
  • 内置变量

    [root@myvm scripts]# awk -F ":" '{print "文件名: "FILENAME "行号: "NR "列数: "NF}' /etc/passwd
    文件名: /etc/passwd行号: 1列数: 7
    文件名: /etc/passwd行号: 2列数: 7
    文件名: /etc/passwd行号: 3列数: 7
    文件名: /etc/passwd行号: 4列数: 7
    ...
    

第 11 章 综合应用案例

发送消息

我们可以利用 Linux 自带的 mesg 和 write 工具,向其它用户发送消息。 需求:实现一个向某个用户快速发送消息的脚本,输入用户名作为第一个参数,后面直 接跟要发送的消息。脚本需要检测用户是否登录在系统中、是否打开消息功能,以及当前发 送消息是否为空。

  • 前置知识

    • who

      • 输出当前登录的所有用户
      • who -T 登录用户是否开启消息接收
    • mesg

      • mesg n : 禁止 其他用户对你的终端进行访问
      • mesg y : 允许 其他用户对你的终端进行访问
    • write

      • 				  		   # 用户名 终端
        [root@myvm scripts]# write kiddkid pts/2
        hi kiddkid
        
  • 实现

    [root@myvm scripts]# vim send_msg.sh
    [root@myvm scripts]# chmod u+x send_msg.sh 
    #!/bin/bash
    
    # 查看用户是否登录
    login_user=$(who | grep -i -m 1 $1 | awk '{print $1}')
    
    if [ -z $login_user ]
    then
            echo "$1 不在线!"
            echo "脚本退出.."
            exit
    fi
    
    # 查看用户是否开启消息功能
    is_allowed=$(who -T | grep -i -m 1 $1 | awk '{print $2}')
    
    if [ $is_allowed != "+" ]
    then
            echo "$1 没有开启消息功能!"
            echo "脚本退出.."
            exit
    fi
    
    # 确认是否有消息发送 
    if [ -z $2 ]
    then
            echo "没有消息发送"
            echo "脚本退出.."
            exit
    fi
    
    # 从参数中获取要发送的消息
    whole_msg=$(echo $* | cut -d " " -f 2-)
    
    # 获取用户登录的终端
    user_terminal=$(who | grep -i -m 1 $1 | awk '{print $2}')
    
    # 写入要发送的消息
    echo $whole_msg | write $login_user $user_terminal
    
    if [ $? != 0 ]
    then
            echo "发送失败!"
    else
            echo "发送成功!"
    fi
    
    exit
    
  • 测试

    [root@myvm scripts]# ./send_msg.sh 
    用法: grep [选项]... PATTERN [FILE]...
    试用‘grep --help’来获得更多信息。
     不在线!
    脚本退出..
    
    [root@myvm scripts]# ./send_msg.sh xiaoming
    xiaoming 不在线!
    脚本退出..
    
    [root@myvm scripts]# ./send_msg.sh kiddkid
    没有消息发送
    脚本退出..
    
    [root@myvm scripts]# ./send_msg.sh kiddkid hi, kiddkid
    发送成功!
    
    [root@myvm scripts]# ./send_msg.sh kiddkid hi, kiddkid
    发送成功!
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值