打怪升级之小白的大数据之旅(四十)<Shell编程>

打怪升级之小白的大数据之旅(四十)

Shell编程

上次回顾

上一章对Linux的常用命令进行了总结分享,命令比较多,VIM是必须要首先熟练的,其次就是按照优先级去练习,本章节对Shell编程进行分享,当然了,我只将后面大数据中可能用到的知识点进行分享,Shell编程真的展开来讲,至少得半个月到一个月。。。我们不是运维,不要纠结,只需要关系我在博客里提到过的知识点哈

Shell概述

  • Shell就是一个命令行解释器,就如同我们在Windows中的cmd一样,它用于接收应用程序或者用户的命令,然后再调用操作系统内核
  • 比如我们java刚开始在命令行使用的javac编译与java运行命令,就是通过Windows的命令行解析器调用操作系统内核,然后执行我们的java代码
  • Linux的shell和Windows的Cmd做的事情是一样的,只不过Linux的Shell更加强大
  • 上面说过,Shell是一个命令行解析器,既然是解析器,那么自然就有很多的版本了,在Linux中提供的Shell解析器有:
    # 查看shell的解释器
    cat /etc/shells 
    /bin/sh
    /bin/bash
    /usr/bin/sh
    /usr/bin/bash
    /bin/tcsh
    /bin/csh
    
  • 在我们使用的CentOS中一般默认使用的是bash 解析器,路径是/bin/bash
  • Shell也是一个功能相当强大的编程语言,具有易编写、易调试、灵活性强的特点

Shell脚本入门程序

  • 入门程序是什么?当然就是hello world啦,Shell编写的程序称为Shell脚本
  • 一般我们编写脚本通常使用脚本的后缀名使用 .sh,sh是bash解析器的一个硬链接,我们可以通过bash xxx.sh进行脚本的运行
  • 脚本的格式(我们习惯性的开头指定解析器的脚本)
    #!/bin/bash
    脚本....
    
  • 第一个脚本程序,首先创建sh文件vim hello.sh
    #!/bin/bash
    echo "hello world"
    
  • 命令行运行: bash hello.sh在这里插入图片描述
  • 运行脚本的方式还可以直接输入脚本的路径进行运行,但是需要设置可执行的权限,例如我直接 chmod -u+x hello,然后直接输入这个文件的路径就可以运行
  • 使用路径进行脚本运行可以使用相对路径和绝对路径两种方式,我建议使用绝对路径,不过更建议使用bash xx.sh脚本的方式运行

Shell变量

如同java一样,Shell也有变量,只不过它有一点点不同

系统定义的变量

  • 我就介绍几个前面遇到的,一般不怎么使用它们,最多使用set这个变量查看一下当前Shell中所有的变量,具体的大家测试一下就懂了
    $HOME
    $PWD
    $SHELL
    $USER
    $PASH
    set
    
  • set命令可以查看当前shell中所有的变量,不过通常是通过管道过滤来查看某个变量的值的,下面我介绍完自定义变量后会掩饰set的用法

自定义变量

  • 自定义变量,就跟java自定义定义变量一样,只不过它不需要声明变量的数据类型
  • 基本语法
    (1)定义变量:变量=值 
    (2)撤销变量:unset 变量
    (3)声明静态变量:readonly变量,注意:不能unset
    
  • 变量定义规则
    (1)变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建议大写。
    (2)等号两侧不能有空格
    (3)在bash中,变量默认类型都是字符串类型,无法直接进行数值运算。
    (4)变量的值如果有空格,需要使用双引号或单引号括起来。
    
  • 注意事项:
    • 当我们使用readonly时,这个变量就无法撤销了…
    • 另外,在shell中,定出来的变量值都是字符串,因此无法做运算,假如我定义了一个变量num=1+1,在输出后,它的值会是字符串的1+1
    • 如果我们定义的变量值有空格,那么我们需要双引号或者单引号包起来
    • 当我们定义变量后,它的作用域只是在当前的目录下,如果想定义全局的变量就需要使用export变量名,这个知识点我们在搭建hadoop服务器的时候会用到
  • 下面进行示例演示,然后演示一下前面提到的set用法,set 通常配合|grep管道符来查看变量的值
    # 自定义一个变量name,值是hello,然后使用set变量查看变量name的值
    name=hello
    set grep|$name
    # 定义变量A
    A=5
    # 给变量A重新赋值
    A=8
    # 撤销变量A
    unset A
    # 声明静态的变量B=2,不能unset\
    readonly B=2
    

特殊变量

  • 特殊变量的作用是命令行传参,假设我们需要通过用户来自定义参数,就需要下面的特殊变量
$n
  • $n用于接收参数的个数
  • 基本语法
    $n	(功能描述:n为数字,$0代表该脚本名称,$1-$9代表第一到第九个参数,十以上的参数,十以上的参数需要用大括号包含,如${10}
  • 示例
    # 1. 创建一个sh脚本文件
    vim parameter.sh
    # 2.通过vim进行脚本编写,接收两个参数
    #!/bin/bash
    echo "$0  $1   $2"
    # 运行脚本,向该文件传递参数
    parameter.sh cls  xz
    # 输出的内容
    ./parameter.sh  cls   xz
    
  • 注意啦,参数是从1开始的,我们定义的0代表的是该脚本文件的名称
$#
  • $#用于统计我们传递参数的个数,通常用于配合循环使用,别急后面会讲到循环
  • 基本语法
    $#	(功能描述:获取所有输入参数个数,常用于循环)
    
  • 示例
    # 创建脚本文件
    vim parameter.sh
    # 编写脚本文件
    #!/bin/bash
    echo "$0  $1   $2"
    echo $#
    # 运行脚本,向该文件传递参数
    bash parameter.sh cls  xz
    # 输出的内容
    parameter.sh cls xz 
    2
    
$*和$@

这两个变量都是代表命令行中所有的参数,具体的区别,我会在循环中演示

  • 基本语法
    $*	(功能描述:这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体)
    $@	(功能描述:这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待)
    
  • 示例
    # 创建sh脚本
    vim parameter.sh
    # 编写脚本文件
    #!/bin/bash
    echo "$0  $1   $2"
    echo $#
    echo $*
    echo $@
    # 运行脚本并传递参数
    bash parameter.sh 1 2 3
    # 输出的内容
    parameter.sh  1   2
    3
    1 2 3
    1 2 3
    
$?
  • 这个参数用于返回最后一次执行命令的返回状态,它有两个返回值0和1,通常情况下我们可以将它理解为布尔值,如果我们最后一次执行命令没有问题,成功了,它返回的值就是0,反之就是1
  • 基本语法
    $?	(功能描述:最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了。)
    
  • 示例
    # 执行脚本
    bash helloworld.sh 
    # 输出结果
    hello world
    # 判断helloworld.sh脚本是否正确执行
    $?
    # 输出结果
    0
    

Shell的运算符

  • 在前面介绍变量的时候说过,Shell默认的变量值都是字符串,那么我们要想做运行就需要通过运算符,运算符比较简单,通过案例就可以明白了
  • 基本语法
    $((运算式))”或“$[运算式]
  • 我建议使用 $[运算式]的方法,更加清爽易读
  • 示例
# 定义变量S,计算(2+3)X4的值
S=$[(2+3)*4]
# 使用echo输出S变量的值
echo $S
# 输出结果
20

条件判断

  • 我们在java中学习运算符时不仅仅是算术运算符,还有比较运算符等等,Shell中同样也有自己的比较运算符,但它有很多的特点,因此我单独将它抽出来

  • 基本语法

    (1)test 表达式
    (2)[ 表达式](注意表达式前后要有空格)
    注意:条件非空即为true,[ 表达式 ]返回true,[] 返回false。
    
  • 常用的判断条件

    比较两个参数

    条件参数参数说明
    =字符串比较
    -eq等于(equal)
    -lt小于(less than)
    -le小于等于(less equal)
    -gt大于(greater than)
    -ge大于等于(greater equal)
    -ne不等于(Not equal)

    按照文件权限进行判断

    条件参数参数说明
    -r有读的权限(read)
    -w-w 有写的权限(write)
    -x有执行的权限(execute)

    按照文件类型进行判断

    条件参数参数说明
    -f文件存在并且是一个常规的文件(file)
    -e文件存在(existence)
    -d文件存在并是一个目录(directory)
  • 比较两个参数是不是有些不适应,没关系,我们理解就好,lt就是less than小于;gt 就是greater 大于, eq就是equal等于,如果组合就是le小于等于…

  • 示例:

# 23是否大于等于22
[ 23 -ge 22 ]
echo $?
# helloworld.sh是否具有写权限
[ -w helloworld.sh ]
echo $?
# /home/xiyou/sunwukong.txt目录中的文件是否存在
[ -e /home/atguigu/cls.txt ]
echo $?

Shell流程控制

  • 学到这里,是不是熟悉感越来越强了?其实所有的编程语言都是大同小异的,基本上的逻辑都一样,只是不同的编程语言有自己的语法规则
  • Shell的流程控制分为 if判断,case语句,for循环和while循环,它们的逻辑就和java一样,只是语法有所区别

if判断

  • 基本语法一
    if [ 条件判断式 ];then 
      程序 
    fi 
    
  • 基本语法二
    if [ 条件判断式 ] 
      then 
        程序 
    elif [ 条件判断式 ]
    	then
    		程序
    else
    	程序
    fi
    
  • 注意事项
    • [ 条件判断式 ],中括号和条件判断式之间必须有空格
    • if后要有空格
    • 我建议使用基本语法二,同样是因为看起来更加清爽
    • if一定要使用fi结束,因为它是通过if的反写来判断是否结束
  • 示例
    # 输入一个数字,如果是1,则输出: 博主大大真帅,如果是2,则输出博主大大不是一般的帅,如果是其它,输出博主大大好自恋
    # 创建脚本文件
    vim ifTest.sh
    # 编写脚本文件
    #!/bin/bash
    if [ $1 -eq "1" ]
        then
            echo "博主大大真帅"
    elif [ $1 -eq "2" ]
        then
            echo "博主大大不是一般的帅"
    else
        echo "博主大大好自恋"
    fi
    
    运行结果:
    在这里插入图片描述

case语句

  • case的用法和java的Switch一样,就是有一些语法区别哈
  • 语法格式
    case $变量名 in 
      "值1") 
        如果变量的值等于值1,则执行程序1 
        ;; 
      "值2") 
        如果变量的值等于值2,则执行程序2 
        ;; 
      …省略其他分支… 
      *) 
        如果变量的值都不是以上的值,则执行此程序 
        ;; 
    esac
    
  • 注意事项
    • case行尾必须为单词“in”,每一个模式匹配必须以右括号“)”结束
    • 双分号“;;”表示命令序列结束,相当于java中的break
    • 最后的“*)”表示默认模式,相当于java中的default
    • 结尾同样必须使用case的反写esac表示结束
  • 示例
    # 输入一个数字,如果是1,则输出春天,如果是2,则输出夏天,如果是3,输出秋天,如果是4,输出冬天,如果是其他则输出:地球上没有这个季节
    # 创建脚本文件
    vim caseTest.sh
    # 编写脚本文件
    #!/bin/bash
    case $1 in
    "1")
        echo "春天"
    ;;
    "2")
        echo "夏天"
    ;;
    "3")
        echo "秋天"
    ;;
    "4")
        echo "冬天"
    ;;
    *)
        echo "地球上没有这个季节"
    esac
    
    运行结果
    在这里插入图片描述

for循环

for循环的语法格式和Java就很像了

  • 基本语法一

    for (( 初始值;循环控制条件;变量变化 )) 
      do 
        程序 
      done
    
  • 基本语法二

    for 变量 in 值1 值2 值3… 
      do 
        程序 
      done
    
  • 示例一

    # 累加1到10的和
    # 创建脚本文件
    vim forTest1.sh
    # 编写脚本文件
    #!/bin/bash
    sum=0
    for((i=0;i<=10;i++))
    do
        sum=$[$sum+$i]
    done
    echo $sum
    

    运行结果
    在这里插入图片描述

  • 示例二

# 打印所有输入参数
# 创建脚本文件
vim forTest2.sh
# 编写脚本
#!/bin/bash
for i in $*
    do
        echo "参数的值是$i"
    done

运行结果在这里插入图片描述

  • 下面我来说明一下$*和$@在循环中的区别,还是上面的案例,只是加了一点改动
    #!/bin/bash
    for i in "$*"
        do
            echo "参数的值是$i"
        done
    echo "---------------------分割线---------------------"
    for j in "$@"
        do
            echo "参数的值是$j"
        done
    
    运行结果
    在这里插入图片描述
  • 在上面的案例中可以知道,$*会将所有的参数当作一个整体,$@会将参数分开,一定注意了,要想让它们有区别,就需要使用双引号将它们包裹起来"\$*","\$@"

while循环

  • 基本语法
    while [ 条件判断式 ] 
      do 
        程序
      done
    
  • 示例
    # 累加1到10的和
    #!/bin/bash
    sum=0
    i=1
    while [ $i -le 10 ]
        do
            sum=$[$sum+$i]
            i=$[$i+1]
        done
    echo $sum
    
    运行结果
    在这里插入图片描述

Shell控制台输入

  • 控制台输入的好处是可以设置定时和提示信息
  • 基本语法
    read(选项)(参数)
    选项:
    -p:指定读取值时的提示符;
    -t:指定读取值时等待的时间(秒)。
    参数
    	变量:指定读取值的变量名
    
  • 示例
    # 提示7秒内,读取控制台输入的名称
    # 创建脚本文件
    # 编写脚本文件
    #!/bin/bash
    read -t 7 -p "Enter your name in 7 seconds " NAME
    echo $NAME
    
    运行结果(咳咳,今天有些自恋了…)
    在这里插入图片描述

Shell函数

  • Shell函数分类系统系统函数和自定义函数,系统函数我们常用的两个就是获取文件名称和文件的路径,自定义函数的作用就不用说了吧,我们学了这么久了…

系统函数

basename
  • 基本语法
    basename [string / pathname] [suffix]  	(功能描述:传递一个包含文件的路径,它会返回文件的名称,suffix为后缀,如果suffix被指定了,那么就会删除后缀
    
  • 示例
    # 获取/opt下的shelldomo中的test的文件名称,带后缀
    basename /opt/shelldemo/test.sh 
    # 不带后缀获取上面的文件名称
    basename /opt/shelldemo/test.sh .sh
    
    运行结果
    在这里插入图片描述
dirname
  • 基本语法
    dirname 文件绝对路径		(功能描述:从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录的部分))
    
  • 示例
# 还是上面的那个文件路径,我只想要test.sh文件的路径,并不想要文件名
dirname /opt/shelldemo/test.sh

运行结果
在这里插入图片描述

自定义函数

  • 语法格式
    [ function ] funname[()]
    {
    	Action;
    	[return int;]
    }
    funname
    
  • 注意事项:
    • 必须在调用函数地方之前,先声明函数,shell脚本是逐行运行。不会像其它语言一样先编译
    • 函数返回值,只能通过$?系统变量获得,可以显示加:return返回,如果不加,将以最后一条命令运行结果,作为返回值。return后跟数值n(0-255)
    • 我们定义完这个函数后,还需要在末尾写入该函数的名称用于调用该函数
  • 示例一
# 计算两个参数的和,普通传参数
#!/bin/bash
function sumNum(){
    sum=0
    sum=$[ $1 + $2 ]
    echo "$sum"
}
echo "计算两个数字的和"
sumNum $1 $2;

运行结果
在这里插入图片描述

  • 示例二
# 计算两个参数的和,使用read传参
#!/bin/bash
function sumNum(){
    sum=0
    sum=$[ $1 + $2 ]
    echo "$sum"
}
echo "计算两个数字的和"
read -p "请输入第一个数字: ": num1;
read -p "请输入第二个数字: ": num2;
sumNum $num1 $num2;

运行结果
在这里插入图片描述

Shell工具

  • Shell工具我主要就介绍两个我们可能会用到的两个,一个cut一个是awk,它们的作用是切割数据,区别就是切割的结果有一点点不同
  • 切割数据就是根据指定的格式将一个文件中的数据进行切割,切割后的数据会变成类似excel表一样的结构,我们切割后就可以使用行和列来获取所需要的数据

cut

  • 语法格式
    cut [选项参数]  filename
    说明:默认分隔符是制表符
    
  • 参数说明
    • -f 列号,提取第几列
    • -d 分隔符,指定分隔符来切割数据
    • -c 指定具体的字符
  • 测试数据(注意:第二列最后的大和帅是两个空格)
    # 创建测试数据
    vim cutData.txt
    # 编写数据
    大  博
    数  主
    据  大
    我   大
    来  真
    了   帅
    !   ~
    

示例一:切割第一列

  • 使用cut按照空格进行切割数据,并获取第一列的数据
    cut -d " " -f 1 cutData.txt
    
    运行结果
    在这里插入图片描述

示例二:切割第二、三列

  • 使用cut按照空格进行切割数据,并获取第二列和第三列的数据
cut -d " " -f 2,3 cutData.txt

运行结果
在这里插入图片描述
示例三:切割出帅这个字

  • 使用cut按照空格进行切割数据,然后配合管道获取所需的数据
    cat cutData.txt | grep "帅" | cut -d " " -f 3
    
    运行结果
    在这里插入图片描述
  • 这种切割的逻辑是,首先切割出帅这一行,然后再切割出帅这个字

awk

  • 在上面使用cut切割时,我们发现,如果空格是多个,它默认其他的空格也会占用一列,通常我们使用的时候,推荐使用的都是awk,它会将所有的空格都切割掉
  • 语法格式
    awk [选项参数] ‘pattern1{action1}  pattern2{action2}...’ filename
    pattern:表示AWK在数据中查找的内容,就是匹配模式
    action:在找到匹配内容时所执行的一系列命令
    
  • 选项参数
    • -F 指定输入文件的分隔符
    • -v 赋值一个自定义的变量
  • 数据准备
    # 我们复制当前系统中的所有用户这个文件用于测试数据
    sudo cp /etc/passwd /opt/demo
    
  • 示例一:搜索passwd文件以root关键字开头的所有行,并输出该行的第7列
    awk -F: '/^root/{print $7}' passwd
    
    运行结果
    在这里插入图片描述
  • 示例二:搜索passwd文件以root关键字开头的所有行,并输出该行的第1列和第7列,中间以“,”号分割
    awk -F: '/^root/{print $1","$7}' passwd
    
    在这里插入图片描述
  • 示例三:只显示/etc/passwd的第一列和第七列,以逗号分割,且在所有行前面添加列名user,shell在最后一行添加"bozhudada,/bin/zuishuai"
    awk -F: 'BEGIN{print "user,shell"} {print $1 "," $7} END{print "博主大大,/bin/zuishuai"}' passwd
    
    运行结果
    在这里插入图片描述
    有点长。。。省略
    在这里插入图片描述
  • 注意:BEGIN 在所有数据读取行之前执行;END 在所有数据执行之后执行
  • 示例四:将passwd文件中的用户id增加数值1并输出
awk -v i=1 -F: '{print $3+i} ' passwd

运行结果
在这里插入图片描述

  • 示例五:统计passwd文件名,每行的行号,每行的列数
    awk -F: '{print "filename:"  FILENAME ", linenumber:" NR  ",columns:" NF}' passwd
    运行结果:
    filename:passwd, linenumber:1,columns:7
    filename:passwd, linenumber:2,columns:7
    filename:passwd, linenumber:3,columns:7
    
  • 示例六:切割IP
     ifconfig ens33 | grep netmask | awk -F " " '{print $2}'
     运行结果:
     192.168.1.100
    

总结

Shell编程的内容就是这么多,Linux命令和Shell的知识点,勤加练习,不用担心,我们大数据的知识点中会经常遇到,好了,下一期,我将为大家正式带来大数据的知识点

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值