• linux shell程序设计


    • shell是unix和linux内核的外壳,它构成了命令或者程序的一个执行环境。不同版本的Unix和linux的shell各有特色,但是都提供了linux命令解释执行的一个基本工作环境。
    • shell脚本程序是利用shell的语法功能所写的一个程序,它是一个纯文本文件,类似于windows环境下的.bat文件,可以让系统自动执行写在shell脚本中的命令,比起windows环境下的.bat文件,它更加类似于高级语言,它可以执行分支、循环、函数等功能。
    • shell是一种解释型程序,不需要经过编译就可以执行。
    • 在centos中执行shell脚本文件的时候,要注意linux并不会默认当前的路径为可以执行的目录,它的所有的可执行文件都会搜索系统的环境变量(可以使用env | grep PATH 查询),环境变量PATH的值指定了可执行的文件的搜索路径。对于以上情况可以有以下的解决方案:
      ① 把当前路径变成可搜索路径(有风险)
      ② 把当前文件移动到可搜索路径下
      ③ 使用./filename
    • 当前路径为可搜索路径后,可以直接输入还是会出错,以为没有执行的权限,有两种解决方法,
      ① chomd修改权限
      ② 使用sh filename,把文件变成sh的一个参数输入

    shell变量

    在shell中,所有的变量都没有定义变量类型,所有的变量都会被看做为字符串变量;在变量名前面加上美元符号$,可以引用变量的值。

    [root@aubin s]# a=456 # 定义一个字符串变量a
    [root@aubin s]# echo $a #把变量a的内容输出
    456
    
    • 1
    • 2
    • 3

    echo表示输出一个数据

    注意以下三条指令的不同

    echo $a # 表示输出a这个变量
    echo "$a" # 表示输出a这个变量
    echo '$a' # 表示输出 $a 这个字符串
    
    • 1
    • 2
    • 3

    使用指令read 可以从键盘中输入一个变量的值,如下:

    [cch@aubin s]$ read b
    www
    [cch@aubin s]$ echo 'b='$b
    b=www
    
    • 1
    • 2
    • 3
    • 4

    if分支语句

    使用[]构成条件分支判断,if 和 fi是成对出现的,而且该语句不能随意的添加或者删减空格。

    echo "Is it morning? Please answer yes or no!"
    read timeofday
    if [$timeofday="yes"];then
    	echo "Good morning!"
    else
    	echo "Good afternoon!"
    fi
    
    exit 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    如果then是单独一行,可以不用分隔符

    echo "Is it morning? Please answer yes or no!"
    read timeofday
    if [$timeofday="yes"]
    then
            echo "Good morning!"
    else
            echo "Good afternoon!"
    fi
    
    exit 0
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    不使用中括号,使用test也可以实现条件语句的编写,但是使用test没有方括号直观

    echo "Is it morning? Please answer yes or no!"
    read timeofday
    if test $timeofday="yes"
    then
            echo "Good morning!"
    else
            echo "Good afternoon!"
    fi
    
    exit 0
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    多分支语句的编写可以使用elif

    echo "Is it morning? Please answer yes or no!"
    read timeofday
    if [$timeofday="yes"]
    then
            echo "Good morning!"
    elif [$timeofday="no"]
    then
            echo "Good afternoon!"
    else
            echo "The answer can not recognize, plese enter again!"
    
    fi
    
    exit 0
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    判断文件

    if [ -f ./pp ] # 判断文件是否存在
    then
    	echo "pp exists"
    fi
    
    if [ -d ./pp ] # 判断文件是否是一个目录,注意中括号与周围的空格
    then
    	echo "pp is a directory"
    else
    	echo "pp is a file"
    fi
    exit 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    if/while语句可以使用以下几种类型的判断

    • 数值比较:-eq(等于)、-ne(不等于)、-gt(大于)、-ge(大于等于)、-lt(小于)、-le(小于等于)
    • 字符串比较:=(等于)、!=(不等于)、-z(字符串长度为零)、-n(字符串长度不为零)
    • 文件测试:-e(文件存在)、-d(目录存在)、-f(文件是否为文本)、-r/-w/-x(文件是否可读/可写/可执行)
    • 逻辑运算:&&(与)、||(或)
    • 其他特殊操作符:()(子shell)、[](数组)

    case语句

    case语句更加适用于多分支语句中

    echo "Is it morning? Please answer yes or no"
    read timeofday
    case "$timeofday" in
    	"yes" ) echo "Good Morning";;
    	"no" ) echo "Good Afternoon";;
    	* ) echo "Please enter again";;
    esac
    exit 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    多个值匹配

    echo "Is it morning? Please answer yes or no"
    read timeofday
    case "$timeofday" in
            yes | Yes | Y ) echo "Good Morning";;
            n* | N* ) echo "Good Afternoon";;
            * ) echo "Please enter again";;
    esac
    exit 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    使用正则表达式

    echo "Is it morning? Please answer yes or no"
    read timeofday
    case "$timeofday" in
            [Yy][Ee][sS]| [Yy]  ) echo "Good Morning";;
            [nN][oO] |[Nn]  ) echo "Good Afternoon";;
            * ) echo "Please enter again";;
    esac
    exit 0
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    for循环

    • foo是一个循环变量,
    • in是关键字,in后面的内容表示循环每一次的值,前面说到,shell的变量都是字符串,所以要循环什么就要在in后面写什么。
    • do …… done中间的表示循环体
    for foo in 1 2 34 # 一共循环三次,in 后面的是循环变量的取值,都为字符串
    do
    	echo $foo
    done
    exit 0
    
    • 1
    • 2
    • 3
    • 4
    • 5

    $(...),以…中的命令的执行结果作为shell变量的取值;除了使用以上的形式,还可以使用esc下面的单引号包括住所需要执行的命令。

    for fo in $(ls p*)
    do
    	echo $fo
    done
    exit 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    for fo in `ls p*`
    do
    	echo $fo
    done
    exit 0
    
    • 1
    • 2
    • 3
    • 4
    • 5

    while循环

    echo "Action!"
    read temp
    
    while [ "$temp" != "hello" ]
    do
            echo "Plase enter again!"
            read temp
    done
    echo $temp
    exit 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    分支判断采用表达式值的判断方式

    -le表示小于等于

    foo=1
    while [ "$foo" -le 20 ]
    do
            echo " $foo : Try again "
            foo=$(($foo + 1))
    done
    exit 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    跳出循环

    • break:跳出当前循环(break默认表示跳出一层循环,break2表示跳出两层循环)
    • exit:退出当前脚本,不再执行exit下方的任何语句
    • continue:忽略本次循环结果,继续执行循环

    位置参数

    位置参数是指函数调用是参数的位置决定其对应的值,在shell中,位置参数从$1开始

    • 无论是函数内部还是函数的外部, $0都表示程序名
    • $@或者$*可以一次性获取所有的参数;
    • $#获取参数的个数
    • ${10}获取第10个参数
    # $0表示函数名; $1表示程序的第一个参数,$i表示程序的第i个参数;参数与其在命令行的位置有关
    echo $0 $1
    # 例如 ls -la 的命令,$0=ls $1=-la
    
    • 1
    • 2
    • 3

    代码示例1:

    #! /bin/bash
    # 这里表示命令行的位置参数,从命令行内键入
    echo $0
    echo $1
    echo $2
    echo $3
    
    foo()
    {
    	# 这里表示函数的位置参数,从函数调用中键入
        echo $0
        echo $1
        echo $2
        echo $3
        echo $4
        echo "function foo\n"
    }
    
    echo "---start---"
    foo 11 22 33 44
    #foo $0 $1 $2 $3 $4
    echo "---end---"
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    # 输出结果
    [cch@aubin s]$ ./pp aa bb cc dd
    ./pp
    aa
    bb
    cc
    ---start---
    ./pp
    11
    22
    33
    44
    function foo\n
    ---end---
    [cch@aubin s]$ 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    代码示例2:

    #! /bin/bash
    
    echo $0
    echo $1
    echo $2
    echo $3
    
    foo()
    {
        echo $0
        echo $1
        echo $2
        echo $3
        echo $4
        echo "function foo\n"
    }
    
    echo "---start---"
    #foo 11 22 33 44
    foo $0 $1 $2 $3 $4 # 这里调用的是命令行的位置参数,从命令行中键入,把命令行中的参数作为函数的参数给函数foo调用
    echo "---end---"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    # 输出结果
    [cch@aubin s]$ ./pp aa bb cc dd
    ./pp
    aa
    bb
    cc
    ---start---
    ./pp
    ./pp # $1的输入结果
    aa
    bb
    cc
    function foo\n
    ---end---
    [cch@aubin s]$ 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 其实位置函数不仅仅是shell的专利,c语言中,我们常看到int main(int argc,char **argv)这样的main函数,这样的main函数也可以从命令行中读取参数,其中argc表示参数的个数这个参数的个数包括了要执行的程序的名字(也就是argc=实际参数的数量+1);argv就是实际传入的参数。
    • 与shell一样,argv[0]表示要执行的程序本身的名字,argv[n]表示要传入的第n个参数。
    #include
    #include
    
    
    int main(int argc,char **argv){
    	printf("argc=%d\n",argc);
    	printf("argv=%s\n",argv[0]);
    	printf("%s\n",argv[1]);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    [cch@aubin s]$ gcc file.c
    [cch@aubin s]$ ./a.out cch1 cch2 
    argc=3 # 输入两个参数为cch1和cch2,但是程序本身./a.out也包括在argc数目内
    argv=./a.out # 程序名称
    cch1 # 第一个参数
    
    • 1
    • 2
    • 3
    • 4
    • 5

    函数

    fun(){}表示是一个函数,大括号之间的内容表示是一个函数体

    fun(){
            echo "This is fun function!"
    
    }
    
    echo "starting"
    fun # 程序本身不会执行,只有当被调用才会开始执行
    echo "ending"
    
    exit 0
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    传递参数

    fun(){
            echo "This is fun function!"
            echo $1 # 获取位置参数,表示是函数内的第一个参数
    }
    
    echo "starting"
    fun "data"
    echo "ending"
    
    exit 0
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    # 这里是输出的结果
    [cch@aubin s]$ ./pp
    starting
    This is fun function!
    data
    ending
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注意,程序的位置参数与函数内的位置参数不是一个概念,出现在函数调用中的$1表示的是程序的位置参数,与在命令行中的第一个参数是一样的;

    fun(){
            echo "This is fun function!"
            echo $2 # 获取位置参数
    }
    
    echo "starting"
    fun "data" $1 #表示命令行的第一个位置参数
    echo "ending"
    
    exit 0
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    # 这里是输出的结果
    [cch@aubin s]$ ./pp
    starting
    This is fun function! # 空行表示没有第二个命令参数
    
    ending
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    流编辑器

    sed工具

    • sed是一个“流编辑”工具,它不面向屏幕,而且非交互式。流编辑器非常适合于执行重复的编辑,这种重复的编辑如果由人工完成将花费大量的时间。
    • sed使用工具按照顺序逐行将文件读入到内存中,然后,他执行该行的所有指定的操作,并且在完成请求的修改之后将该行返回内存中,以将其转储到中断。完成这一行的所有操作之后,它读取文件的下一行,重复以上步骤,知道它完成整个文件。sed默认把内容输出到屏幕,保持源文件不会被修改。

    sed的语法:sed [options] '{command}' [filename]

    -e 表示后面的指令同步执行
    
    • 1
    [cch@aubin ~]$ echo "the tiger cubs will meet on Tuesday after scool" | sed -e 's/tiger/wolf/' -e 's/after/before/'
    the wolf cubs will meet on Tuesday before scool
    
    • 1
    • 2

    awk工具

    awk是一个优秀的样式扫描与处理工具,其功能大大强与sed和grep;awk几乎可以完成grep和sed所能完成的全部的工作,同时它号可以进行样式的装入、流控制、数学运算符、进程控制语句甚至内置的变量和函数。它具备了一个完整的语言所应该具备的几乎所有的特性。awk有自己的程序设计语言为 样式扫描和处理语言。

    awk [-F separator] ‘pattern’ {action}’ filename

    $1 表示第一列的意思,匹配搭配 :0 行,并且输出第一列的信息
    
    • 1
    [cch@aubin ~]$ who | awk '/:0 /{print $1}'
    cch
    
    • 1
    • 2

    应用示例

    which命令的shell脚本实现

    which主要是用来查找一些可执行文件的存放在哪一个可执行的路径下。

    [cch@aubin ~]$ which file
    /usr/bin/file
    
    • 1
    • 2
    # 以上系统命令可以使用sed来实现
    for i in `env | grep PATH | sed -e 's/^PATH=//' -e 's/:/ /g'`
    do
    find $i -name $1 -print 2>/dev/null
    done
    
    • 1
    • 2
    • 3
    • 4
    • 5
    [cch@aubin s]$ ./pp file
    /usr/bin/file
    [cch@aubin s]$ 
    
    • 1
    • 2
    • 3

    以上命令的意思是:

    • `表示单引号内的都是可执行的命令
    • env是一个系统命令,用于查找当前系统的可执行路径
    • env | grep PATH | sed,把env的结果作为右边的输入,检查env输出中的PATH匹配项,并且给到sed
    • -e 表示两个指令同步执行
    • 's/^PATH=//'把首字串为PATH=的替换成空
    • 's/:/ /g'把所有的冒号替换成空格,并且全文替换。
    • find $i -name $1 -print把输入的第一个参数作为find的查找,去查找到对应的结果并且输出
    • 2>/dev/null可能会出现错误,把错误重定向/dev/null中,避免屏幕显示出错误
    # 还可以使用awk来实现,awk有内嵌的函数
    for i in `set | grep PATH |awk  '{sub(/^PATH=/,"")}{gsub(/:/," ")}{print $0}'`
    do
    find $i -name $1 -print 2>/dev/null
    done
    exit 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    以上的命令解释如下:

    • subgsub是awk内嵌的两个函数,前者表示替换,后者表示全文替换
    • {print $0}表示输出全部的列,作为in 后面的内容
    • set与env的命令是一样的

    讨论

    问题一:如何定义和使用shell变量,给出一个例子

    讨论:使用shell变量有三种方法,一种是用等号直接赋值,比如a=123;第二种是从键盘中读入,比如read b;第三种是使用for循环变量,比如 for i in a b c,可以对i循环赋值为a b c。

    问题二:if/while语句可以利用多少种类型的判断?

    讨论:if/while语句可以有三种类型的判断,一种是字符串的判断,比如判断写入的数据是否是yes/no;第二种是文件的判断,比如使用 -f 判断文件是否存在,使用 -d 判断文件是否是一个目录;第三种是判断一个值是否相等,shell变量虽然都是字符串,但是可以使用$()对字符串取值。

    问题三:什么是正则表达式,怎么样使用正则表达式去匹配得更加清楚

    讨论:正则表达式可以用来匹配符合某一种规则的字符,以case语句中,需要匹配no的各种大小写的可能性,可以使用正则匹配 [Nn][Oo] | [Nn] ,这样可以使得条件表达式更加简洁。

    问题四:程序(可执行文件)的参数是什么,函数的参数是什么,举例说明如何使用这些参数。

    讨论:程序的位置参数和函数的位置参数是不同的,①程序的参数指的是整一个程序(命令的)参数,比如在命令行中输入ls -la ,该命令中的 -la 就是该命令的第一个参数,用 $1 表示;②函数的参数表示函数调用时传递的参数,跟在函数调用的后面。

    问题五:什么是sed,什么是awk,举例说明怎么使用他们

    讨论:详情看上面的介绍。

  • 相关阅读:
    跳出Lambda表达式forEach()循环解决思路
    微服务实战微服务网关Gateway入门与实战
    python文本操作
    第一个简单爬虫:获取页面
    使用HTML+CSS实现一个静态页面——面包蛋糕 (9页)
    PixelSNAIL论文代码学习(3)——自注意力机制的实现
    Ubuntu22.04版本侧边栏和顶部栏隐藏与其他版本不同
    Springboot+Mybatis-puls整合
    win10系统任务栏图标变成白色的解决办法
    AI伦理:科技发展中的人性之声
  • 原文地址:https://blog.csdn.net/CodePlayMe/article/details/133612594