• Shell


    一、Shell入门简介

    1.1 什么是shell

    1.2

    1.3 第一个伟大的shell脚本

    #创建HelloWorld.sh文件
    [lln@hadoop102 shell]$ touch HelloWorld.sh
    #编辑HelloWorld.sh文件
    [lln@hadoop102 shell]$ vim HelloWorld.sh
    #查看HelloWorld.sh文件
    [root@hadoop102 shell]# cat HelloWorld.sh
    #!/bin/bash
    # This is ower first shell
    # by author lln 2022.8.25
    echo "hello world"
    #查看文件目录
    [lln@hadoop102 shell]$ ll
    总用量 4
    -rw-rw-r--. 1 lln lln 84 825 09:46 HelloWorld.sh
    #运行HelloWorld.sh脚本
    [lln@hadoop102 shell]$ ./HelloWorld.sh
    -bash: ./HelloWorld.sh: 权限不够
    #赋予执行权限
    [root@hadoop102 shell]# chmod +x HelloWorld.sh
    #再次运行HelloWorld.sh脚本
    [root@hadoop102 shell]# ./HelloWorld.sh
    hello world
    [root@hadoop102 shell]# 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

     

    1.4 shell脚本执行方式

     

    在新进程中运行shell脚本
     

    • 将shell脚本作为程序运行

    Shell 脚本也是一种解释执行的程序,可以在终端直接调用(需要使用 chmod 命令给 Shell 脚本加上执行权限),如下所示:

    在这里插入图片描述

    #! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。

    通过这种方式运行脚本,脚本文件第一行的#!/bin/bash一定要写对,好让系统查找到正确的解释器。

    chmod +x表示给 a.sh 增加执行权限。

    ./表示当前目录,整条命令的意思是执行当前目录下的 a.sh 脚本。如果不写./,Linux 会到系统路径(由 PATH环境变量指定)下查找 a.sh,而系统路径下显然不存在这个脚本,所以会执行失败。

     

    • 将shell脚本作为参数传递给Bash解释器

    直接运行 Bash 解释器,将脚本文件的名字作为参数传递给 Bash。

    通过这种方式运行脚本,不需要在脚本文件的第一行指定解释器信息,写了也没用。

    更加简洁的写法是运行 bash 命令。bash 是一个外部命令,Shell 会在 /bin 目录中找到对应的应用程序,也即 /bin/bash,这点我们已在《Shell命令的本质到底是什么》一节中提到。

    在这里插入图片描述
    这两种写法在本质上是一样的:第一种写法给出了绝对路径,会直接运行 Bash 解释器;第二种写法通过 bash 命令找到 Bash 解释器所在的目录,然后再运行,只不过多了一个查找的过程而已。

     

    检测是否开启了新进程

    Linux 中的每一个进程都有一个唯一的 ID,称为 PID,使用$$变量就可以获取当前进程的 PID。

    在这里插入图片描述
    进程的 PID 都不一样,当然就是两个进程了。

     

    在当前进程中运行shell脚本

    source 是 Shell 内置命令的一种,它会读取脚本文件中的代码,并依次执行所有语句。你也可以理解为,source 命令会强制执行脚本文件中的全部命令,而忽略脚本文件的权限。

    source 命令的用法为:

    source filename
    
    • 1

    也可以简写为:

    . filename
    
    • 1

    两种写法的效果相同。对于第二种写法,注意点号.文件名中间有一个空格

    在这里插入图片描述
    使用 source 命令不用给脚本增加执行权限,并且写不写./都行。

    进程的 PID 都是一样的,当然是同一个进程了。

     

    现有一a.sh脚本

    #!/bin/bash
    echo "step 1 sleeping"
    sleep 200
    echo "step 2 sleeping"
    sleep 200
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • ./a.shsh ./a.shbash ./a.sh ,此三种执行脚本的方式都是重新启动一个shell,在子shell中执行此脚本,脚本中设置的变量在脚本执行完毕后不会保存。(但是若 script.sh 脚本不是以 #!/bin/bash 开头,那么也不会在子进程中执行。) ./a.sh将a.sh当成一个文件执行,此时需要x运行权限,同时有两个进程进行:a.sh和sleep。如果在执行到第一个sleep时终止脚本,a.sh和sleep一起终止,并且第二个sleep不会执行,因为整个a.sh运行已经终止。
    • source ./a.sh   和 . ./a.sh   的执行方式是等价的,即这两种执行方式都是在当前shell进程中执行此脚本,而不是重新启动一个shell在子shell进程中执行此脚本,并且脚本中设置的变量在脚本执行完毕后会保存下来。
    • source是Shell(准确地说是Bash)的内置命令,在Bourne Shell中的等价命令是一个点.,即点命令。用source命令执行脚本文件时,是在当前Shell进程中执行,而不是像./sh方式一样在新的Shell进程中执行,因此早先设置的变量在脚本里是可以读取到的。不需要执行权限,有读取权限(r权限)即可。如果在执行第1个sleep时按ctrl+c终止,那么第2个sleep接着运行,直到脚本所有命令执行完。
    • source一般不用来执行业务脚本,最常见用途是在某些初始化脚本修改之后使其立即生效,即source /etc/profile这样。

     

    二、shell变量

    2.1 shell变量介绍

    Shell编程中变量分为三种,分别是系统变量、环境变量和用户变量。
    Shell变量名在定义时,首个字符必须为字母(a-z,A-Z),不能以数字开头,中间不能有空格,可以使用下划线_,不能使用-,也不能使用标点符号等。
    等号两侧不能有空格。

    2.2 shell系统变量

    # 系统变量,主要是用于对参数判断和命令返回值判断时使用,系统变量详解如下:
    
    $0 		当前脚本的名称;
    $n 		当前脚本的第n个参数,n=1,2,9;
    $* 		当前脚本的所有参数(不包括程序本身);
    $# 		当前脚本的参数个数(不包括程序本身);
    $? 		令或程序执行完后的状态,返回0表示执行成功;
    $$ 		程序本身的PID号。
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.3 shell环境变量

    环境变量,主要是在程序运行时需要设置,环境变量详解如下:
    
    PATH  		命令所示路径,以冒号为分割;
    HOME  		打印用户家目录;
    SHELL 		显示当前Shell类型;
    USER  		打印当前用户名;
    ID    		打印当前用户id信息;
    PWD   		显示当前所在路径;
    TERM  		打印当前终端类型;
    HOSTNAME    显示当前主机名;
    PS1         定义主机命令提示符的;
    HISTSIZE    历史命令大小,可通过 HISTTIMEFORMAT 变量设置命令执行时间;
    RANDOM      随机生成一个 032767 的整数;
    HOSTNAME    主机名
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2.4 shell用户变量

    # 用户变量又称为局部变量,主要用在Shell脚本内部或者临时局部使用,系统变量详解如下:
    a=rivers 				       自定义变量AHttpd_sort=httpd-2.4.6-97.tar  自定义变量N_SOFT;
    BACK_DIR=/data/backup/         自定义变量BACK_DIR;
    IPaddress=10.0.0.1			   自定义变量IP1;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.5 变量的定义

    在这里插入图片描述

    在这里插入图片描述

    2.6 Shell变量的作用域

    Shell 变量的作用域可以分为三种:

    • 有的变量只能在函数内部使用,这叫做局部变量(local variable);
    • 有的变量可以在当前 Shell 进程中使用,这叫做全局变量(global variable);
    • 而有的变量还可以在子进程中使用,这叫做环境变量(environment variable)。

    2.7 局部变量

    Shell 也支持自定义函数,但是 Shell 函数和 C++、Java、C# 等其他编程语言函数的一个不同点就是:在 Shell 函数中定义的变量默认也是全局变量,它和在函数外部定义变量拥有一样的效果。

    #!/bin/bash
    
    #定义函数
    function func(){
        a=99
    }
    
    #调用函数
    func
    
    #输出函数内部的变量
    echo $a
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    输出结果:
    99

    a 是在函数内部定义的,但是在函数外部也可以得到它的值,证明它的作用域是全局的,而不是仅限于函数内部。

    要想变量的作用域仅限于函数内部,可以在定义时加上 local 命令,此时该变量就成了局部变量。

    #!/bin/bash
    
    #定义函数
    function func(){
        local a=99
    }
    
    #调用函数
    func
    
    #输出函数内部的变量
    echo $a
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    输出结果为空,表明变量 a 在函数外部无效,是一个局部变量。

    Shell 变量的这个特性和 JavaScript 中的变量是类似的。在 JavaScript 函数内部定义的变量,默认也是全局变量,只有加上var关键字,它才会变成局部变量。

     

    2.8 全局变量

    所谓全局变量,就是指变量在当前的整个 Shell 进程中都有效。
    每个 Shell 进程都有自己的作用域,彼此之间互不影响。
    在 Shell 中定义的变量,默认就是全局变量。

    想要实际演示全局变量在不同 Shell 进程中的互不相关性,可在图形界面下同时打开两个 Shell,或使用两个终端远程连接到服务器(SSH)。

    首先打开一个 Shell 窗口,定义一个变量 a 并赋值为 99,然后打印,这时在同一个 Shell 窗口中是可正确打印变量 a 的值的。然后再打开一个新的 Shell 窗口,同样打印变量 a 的值,但结果却为空,如下图所示。
    在这里插入图片描述

    这说明全局变量 a 仅仅在定义它的第一个 Shell 进程中有效,对新的 Shell 进程没有影响。

    需要强调的是,全局变量的作用范围是当前的 Shell 进程,而不是当前的 Shell 脚本文件,它们是不同的概念。打开一个 Shell 窗口就创建了一个 Shell 进程,打开多个 Shell 窗口就创建了多个 Shell 进程,每个 Shell 进程都是独立的,拥有不同的进程 ID。在一个 Shell 进程中可以使用 source 命令执行多个 Shell 脚本文件,此时全局变量在这些脚本文件中都有效。

    例如:
    a.sh

    #!/bin/bash
    echo $a
    b=200
    
    • 1
    • 2
    • 3

    b.sh

    #!/bin/bash
    echo $b
    
    • 1
    • 2

    在这里插入图片描述

    这三条命令都是在一个进程中执行的,从输出结果可以发现,在 Shell 窗口中以命令行的形式定义的变量 a,在 a.sh 中有效;在 a.sh 中定义的变量 b,在 b.sh 中也有效,变量 b 的作用范围已经超越了 a.sh。

    注意,必须在当前进程中运行 Shell 脚本,不能在新进程中运行 Shell 脚本。

    2.9 环境变量

    全局变量只在当前 Shell 进程中有效,对其它 Shell 进程和子进程都无效。如果使用export命令将全局变量导出,那么它就在所有的子进程中也有效了,这称为“环境变量”。

    环境变量被创建时所处的 Shell 进程称为父进程,如果在父进程中再创建一个新的进程来执行 Shell 命令,那么这个新的进程被称作 Shell 子进程。当 Shell 子进程产生时,它会继承父进程的环境变量为自己所用,所以说环境变量可从父进程传给子进程。不难理解,环境变量还可以传递给孙进程。

    注意,两个没有父子关系的 Shell 进程是不能传递环境变量的,并且环境变量只能向下传递而不能向上传递,即“传子不传父”。

    创建 Shell 子进程最简单的方式是运行 bash 命令

    请添加图片描述

    通过exit命令可以一层一层地退出 Shell。

    演示环境变量的使用:

    [redhat@localhost ~]$ a=100      #定义一个全局变量
    [redhat@localhost ~]$ echo $a    #在当前Shell中输出a,成功
    100
    [redhat@localhost ~]$ bash	     #进入Shell子进程
    [redhat@localhost ~]$ echo $a	 #在子进程中输出a,失败
    
    [redhat@localhost ~]$ exit	     #退出Shell子进程,返回上一级Shell
    exit
    [redhat@localhost ~]$ export a   #将a导出为环境变量
    [redhat@localhost ~]$ bash	     #重新进入Shell子进程
    [redhat@localhost ~]$ echo $a	 #在子进程中再次输出a,成功
    100
    [redhat@localhost ~]$ exit	     #退出Shell子进程
    exit
    [redhat@localhost ~]$ exit	     #退出父进程,结束整个Shell会话
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    可以发现,默认情况下,a 在 Shell 子进程中是无效的;使用 export 将 a 导出为环境变量后,在子进程中就可以使用了。

    export a这种形式是在定义变量 a 以后再将它导出为环境变量,如果想在定义的同时导出为环境变量,可以写作export a=22。

    我们一直强调的是环境变量在 Shell 子进程中有效,并没有说它在所有的 Shell 进程中都有效;如果你通过终端创建了一个新的 Shell 窗口,那它就不是当前 Shell 的子进程,环境变量对这个新的 Shell 进程仍然是无效的。第一个窗口中的环境变量 a 在第二个窗口中就无效。

    在这里插入图片描述

    环境变量也是临时的

    通过 export 导出的环境变量只对当前 Shell 进程以及所有的子进程有效,如果最顶层的父进程被关闭了,那么环境变量也就随之消失了,其它的进程也就无法使用了,所以说环境变量也是临时的。

    如果我想让一个变量在所有 Shell 进程中都有效,不管它们之间是否存在父子关系,该怎么办呢?

    只有将变量写入 Shell 配置文件中才能达到这个目的!Shell 进程每次启动时都会执行配置文件中的代码做一些初始化工作,如果将变量放在配置文件中,那么每次启动进程都会定义这个变量。

    2.10 命令替换

    Shell 命令替换是指将命令的输出结果赋值给某个变量。比如,在某个目录中输入 ls 命令可查看当前目录中所有的文件,但如何将输出内容存入某个变量中呢?这就需要使用命令替换了,这也是 Shell 编程中使用非常频繁的功能。

    Shell 中有两种方式可以完成命令替换,一种是反引号,一种是$(),使用方法如下:

    variable=`commands`
    variable=$(commands)
    
    • 1
    • 2

    其中,variable 是变量名,commands 是要执行的命令。commands 可以只有一个命令,也可以有多个命令,多个命令之间以分号;分隔。

    例如,date 命令用来获得当前的系统时间,使用命令替换可以将它的结果赋值给一个变量。

    #!/bin/bash
    begin_time=`date`    #开始时间,使用``替换
    sleep 20s            #休眠20秒
    finish_time=$(date)  #结束时间,使用$()替换
    echo "Begin time: $begin_time"
    echo "Finish time: $finish_time"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    运行脚本,20 秒后可以看到输出结果:

    Begin time: 20220826日 星期五 09:59:58 CST
    Finish time: 20220826日 星期五 10:00:18 CST
    
    • 1
    • 2

    使用 data 命令的%s格式控制符可以得到当前的 UNIX 时间戳,这样就可以直接计算脚本的运行时间了。UNIX 时间戳是指从 1970 年 1 月 1 日 00:00:00 到目前为止的秒数。

    #!/bin/bash
    begin_time=`date +%s`    #开始时间,使用``替换
    sleep 20s                #休眠20秒
    finish_time=$(date +%s)  #结束时间,使用$()替换
    run_time=$((finish_time - begin_time))  #时间差
    echo "begin time: $begin_time"
    echo "finish time: $finish_time"
    echo "run time: ${run_time}s"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    运行脚本,20 秒后可以看到输出结果:

    begin time: 1555639864
    finish time: 1555639884
    run time: 20s
    
    • 1
    • 2
    • 3

    第 5 行代码中的(( ))是 Shell 数学计算命令。和 C++、C#、Java 等编程语言不同,在 Shell 中进行数据计算不那么方便,必须使用专门的数学计算命令,(( ))就是其中之一。

    注意,如果被替换的命令的输出内容包括多行(也即有换行符),或者含有多个连续的空白符,那么在输出变量时应该将变量用双引号包围,否则系统会使用默认的空白符来填充,这会导致换行无效,以及连续的空白符被压缩成一个。

    #!/bin/bash
    LSL=`ls -l`
    echo $LSL  #不使用双引号包围
    echo "--------------------------"  #输出分隔符
    echo "$LSL"  #使用引号包围
    
    • 1
    • 2
    • 3
    • 4
    • 5

    运行结果:

    total 8 drwxr-xr-x. 2 root root 21 71 2016 abc -rw-rw-r--. 1 mozhiyan mozhiyan 147 1031 10:29 demo.sh -rw-rw-r--. 1 mozhiyan mozhiyan 35 1031 10:20 demo.sh~
    --------------------------
    total 8
    drwxr-xr-x. 2 root     root      21 71 2016 abc
    -rw-rw-r--. 1 mozhiyan mozhiyan 147 1031 10:29 demo.sh
    -rw-rw-r--. 1 mozhiyan mozhiyan  35 1031 10:20 demo.sh
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    所以,为了防止出现格式混乱的情况,我建议在输出变量时加上双引号。

     

    再谈反引号和 $ ()

    原则上讲,上面提到的两种变量替换的形式是等价的,可以随意使用;但是,反引号毕竟看起来像单引号,有时候会对查看代码造成困扰,而使用 $ () 就相对清晰,能有效避免这种混乱。而且有些情况必须使用 $ (), $ () 支持嵌套,反引号不行。

    下面的例子演示了使用计算 ls 命令列出的第一个文件的行数,这里使用了两层嵌套。

    [c.biancheng.net]$ Fir_File_Lines=$(wc -l $(ls | sed -n '1p'))
    [c.biancheng.net]$ echo "$Fir_File_Lines"
    36 anaconda-ks.cfg
    
    • 1
    • 2
    • 3

    要注意的是,$ () 仅在 Bash Shell 中有效,而反引号可在多种 Shell 中使用。所以这两种命令替换的方式各有特点,究竟选用哪种方式全看个人需求。

    2.11 位置参数

    运行Shell脚本文件时我们可以给它传递一些参数,这些参数在脚本文件内部可以使用$n的形式来接收,例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。

    同样,在调用函数时也可以传递参数。Shell 函数参数的传递和其它编程语言不同,没有所谓的形参和实参,在定义函数时也不用指明参数的名字和数目。换句话说,定义 Shell 函数时不能带参数,但是在调用函数时却可以传递参数,这些传递进来的参数,在函数内部就也使用$n的形式接收,例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。

    这种通过$n的形式来接收的参数,在 Shell 中称为位置参数。

    在讲解变量的命名时,我们提到:变量的名字必须以字母或者下划线开头,不能以数字开头;但是位置参数却偏偏是数字,这和变量的命名规则是相悖的,所以我们将它们视为“特殊变量”。

    • 给脚本文件传递位置参数

    test003.sh

    #!/bin/bash
    echo "Language: $1"
    echo "Url: $2"
    
    • 1
    • 2
    • 3

    运行 test.sh,并附带参数:

    在这里插入图片描述

    • 给函数传递位置参数
    #!/bin/bash
    #定义函数
    function func(){
        echo "Language: $1"
        echo "URL: $2"
    }
    #调用函数
    func C++ http://c.biancheng.net/cplus/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    运行:

    [mozhiyan@localhost demo]$ . ./test.sh
    Language: C++
    URL: http://c.biancheng.net/cplus/
    
    • 1
    • 2
    • 3

    注意事项
    如果参数个数太多,达到或者超过了 10 个,那么就得用${n}的形式来接收了,例如 10 、 {10}、 10{23}。{ }的作用是为了帮助解释器识别参数的边界,这跟使用变量时加{ }是一样的效果。

    2.12 特殊变量

    Shell特殊变量及其含义

    在这里插入图片描述

    • 给脚本文件传递参数
    #!/bin/bash
    echo "Process ID: $$"
    echo "File Name: $0"
    echo "First Parameter : $1"
    echo "Second Parameter : $2"
    echo "All parameters 1: $@"
    echo "All parameters 2: $*"
    echo "Total: $#"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    运行,并附带参数:

    [mozhiyan@localhost demo]$ . ./test.sh Shell Linux
    Process ID: 5943
    File Name: bash
    First Parameter : Shell
    Second Parameter : Linux
    All parameters 1: Shell Linux
    All parameters 2: Shell Linux
    Total: 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 给函数传递参数
    #!/bin/bash
    #定义函数
    function func(){
        echo "Language: $1"
        echo "URL: $2"
        echo "First Parameter : $1"
        echo "Second Parameter : $2"
        echo "All parameters 1: $@"
        echo "All parameters 2: $*"
        echo "Total: $#"
    }
    #调用函数
    func Java http://c.biancheng.net/java/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    运行结果:

    Language: Java
    URL: http://c.biancheng.net/java/
    First Parameter : Java
    Second Parameter : http://c.biancheng.net/java/
    All parameters 1: Java http://c.biancheng.net/java/
    All parameters 2: Java http://c.biancheng.net/java/
    Total: 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    三、shell流程控制语句

    3.1 if条件语句

    3.1.1 if分支

    在这里插入代码片
    
    • 1

    3.1.2 if常见判断运算符

    3.1.3 判断crond进程是否在运行

     

    echo 命令

    echo是一个Shell内建命令,用来在终端输出字符串,并在最后加默认加上换行符。

    【实例】

    #!/bin/bash
    name="Shell教程"
    url="http://c.biancheng.net/shell/"
    echo "读者,你好!"  #直接输出字符串
    echo $url  #输出变量
    echo "${name}的网址是:${url}"  #双引号包围的字符串中可以解析变量
    echo '${name}的网址是:${url}'  #单引号包围的字符串中不能解析变量
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    运行结果:

    读者,你好!
    http://c.biancheng.net/shell/
    Shell教程的网址是:http://c.biancheng.net/shell/
    ${name}的网址是:${url}
    
    • 1
    • 2
    • 3
    • 4

    不换行

    echo命令输出结束后默认会换行,如果不希望换行,可以加上-n参数,如下所示:

    #!/bin/bash
    name="Tom"
    age=20
    height=175
    weight=62
    echo -n "${name} is ${age} years old, "
    echo -n "${height}cm in height "
    echo "and ${weight}kg in weight."
    echo "Thank you!"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    运行结果:

    Tom is 20 years old, 175cm in height and 62kg in weight.
    Thank you!
    
    • 1
    • 2

    输出转义字符

    默认情况下,echo 不会解析以反斜杠\开头的转义字符。比如,\n表示换行,echo 默认会将它作为普通字符对待。

    [root@localhost ~]# echo "hello \nworld"
    hello \nworld
    
    • 1
    • 2

    可以添加-e参数来让 echo 命令解析转义字符。

    [root@localhost ~]# echo -e "hello \nworld"
    hello
    world
    
    • 1
    • 2
    • 3

    \c转义字符
    有了-e参数,我们也可以使用转义字符-c来强制echo命令不换行了。

    #!/bin/bash
    name="Tom"
    age=20
    height=175
    weight=62
    echo -e "${name} is ${age} years old, \c"
    echo -e "${height}cm in height \c"
    echo "and ${weight}kg in weight."
    echo "Thank you!"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    运行结果:

    Tom is 20 years old, 175cm in height and 62kg in weight.
    Thank you!
    
    • 1
    • 2

     

    read命令

    read是Shell的内置命令,用来从标准输入中读取数据并赋值给变量。如果没有进行重定向,默认就是从键盘读取用户输入的数据;如果进行了重定向,那么可以从文件中读取数据。

    read命令的用法为:

    read [-options] [variables]
    
    • 1

    options表示选项,如下表所示;variables表示用来存储数据的变量,可以有一个或多个,如果输入多个数据,则第一个数据给第一个变量,第二个数据给第二个变量,如果输入数据个数过多,则最后所有的值都给第一个变量。如果太少输入不会结束。

    optionsvariables都是可选的,如果没有提供变量名,那么读取的数据将存放到环境变量REPLY中。

    在这里插入图片描述

    【实例1】使用read命令给多个变量赋值

    #!/bin/bash
    read -p "Enter some information > " name url age
    echo "网站名字:$name"
    echo "网址:$url"
    echo "年龄:$age"
    
    • 1
    • 2
    • 3
    • 4
    • 5

    运行结果:

    Enter some information > C语言中文网 http://c.biancheng.net 7
    网站名字:C语言中文网
    网址:http://c.biancheng.net
    年龄:7
    
    • 1
    • 2
    • 3
    • 4

    注意,必须在一行内输入所有的值,不能换行,否则只能给第一个变量赋值,后续变量都会赋值失败。

    本例还使用了-p选项,该选项会用一段文本来提示用户输入。

    【实例2】只读取一个字符

    #!/bin/bash
    read -n 1 -p "Enter a char > " char
    printf "\n"  #换行
    echo $char
    
    • 1
    • 2
    • 3
    • 4

    运行结果:

    Enter a char > 1
    1
    
    • 1
    • 2

    -n 1表示只读取一个字符。运行脚本后,只要用户输入一个字符,立即读取结束,不用等待用户按下回车键。

    printf "\n"语句用来达到换行的效果,否则 echo 的输出结果会和用户输入的内容位于同一行,不容易区分。

    【实例3】在指定时间内输入密码

    #!/bin/bash
    if
        read -t 20 -sp "Enter password in 20 seconds(once) > " pass1 && printf "\n" &&  #第一次输入密码
        read -t 20 -sp "Enter password in 20 seconds(again)> " pass2 && printf "\n" &&  #第二次输入密码
        [ $pass1 == $pass2 ]  #判断两次输入的密码是否相等
    then
        echo "Valid password"
    else
        echo "Invalid password"
    fi
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    这段代码中,我们使用&&组合了多个命令,这些命令会依次执行,并且从整体上作为if语句的判断条件,只要其中一个命令执行失败(退出状态为非 0 值),整个判断条件就失败了,后续的命令也就没有必要执行了。

    如果两次输入密码相同,运行结果为:

    Enter password in 20 seconds(once) >
    Enter password in 20 seconds(again)>
    Valid password
    
    • 1
    • 2
    • 3

    如果两次输入密码不同,运行结果为:

    Enter password in 20 seconds(once) >
    Enter password in 20 seconds(again)>
    Invalid password
    
    • 1
    • 2
    • 3

    如果第一次输入超时,运行结果为:

    Enter password in 20 seconds(once) > Invalid password
    
    • 1

    如果第二次输入超时,运行结果为:

    Enter password in 20 seconds(once) >
    Enter password in 20 seconds(again)> Invalid password
    
    • 1
    • 2

    【实例4】读文件

    每次调用read命令都会读取文件中的"一行"文本。当文件没有可读的行时,read命令将以非零状态退出。

    读取文件的关键是如何将文本中的数据传送给read命令。

    最常用的方法是对文件使用cat命令并通过管道将结果直接传送给包含read命令的while命令

    alias

    alias用来给命令创建一个别名。

    若直接输入alias且不带任何参数,则会列出当前进程中使用了哪些别名。

    例如llls -l的效果一样。

    [redhat@localhost shell]$ alias
    alias egrep='egrep --color=auto'
    alias fgrep='fgrep --color=auto'
    alias grep='grep --color=auto'
    alias l.='ls -d .* --color=auto'
    alias ll='ls -l --color=auto'
    alias ls='ls --color=auto'
    alias vi='vim'
    alias which='(alias; declare -f) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot'
    alias xzegrep='xzegrep --color=auto'
    alias xzfgrep='xzfgrep --color=auto'
    alias xzgrep='xzgrep --color=auto'
    alias zegrep='zegrep --color=auto'
    alias zfgrep='zfgrep --color=auto'
    alias zgrep='zgrep --color=auto'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    为了让我们使用方便,Shell 会给某些命令默认创建别名。

    不学了,学锤子,学sql去了。。。。。。。。。。。。。。。

    不学了,学锤子,学sql去了。。。。。。。。。。。。。。。

    不学了,学锤子,学sql去了。。。。。。。。。。。。。。。

    不学了,学锤子,学sql去了。。。。。。。。。。。。。。。

    不学了,学锤子,学sql去了。。。。。。。。。。。。。。。

    不学了,学锤子,学sql去了。。。。。。。。。。。。。。。

    不学了,学锤子,学sql去了。。。。。。。。。。。。。。。

    不学了,学锤子,学sql去了。。。。。。。。。。。。。。。

    不学了,学锤子,学sql去了。。。。。。。。。。。。。。。

    不学了,学锤子,学sql去了。。。。。。。。。。。。。。。

    不学了,学锤子,学sql去了。。。。。。。。。。。。。。。

    不学了,学锤子,学sql去了。。。。。。。。。。。。。。。

  • 相关阅读:
    从0到1,手把手带你开发截图工具ScreenCap------001实现基本的截图功能
    MySQL补充开窗函数
    Numpy 和 random中的随机函数用法汇总
    正则表达式快速入门笔记
    变分贝叶斯深度学习综述
    dolphinscheduler3.1.1 部署
    Vue3简单项目流程分享——工作室主页
    SSO单点登录流程详解
    uniapp开发h5 调用微信sdk 全网最全指南!!!! 血泪史!!!
    element ui 时间日期选择器 el-date-picker 报错 Prop being mutated: “placement“
  • 原文地址:https://blog.csdn.net/lln1540295459/article/details/126518569