shell编程

Posted pier~呀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shell编程相关的知识,希望对你有一定的参考价值。

shell编程

概述

Shell是一个命令行解释器,它接收应用程序/用户命令,然后调用操作系统内核

Shell还是一个功能相当强大的编程语言,易编写、易调试、灵活性强。

注:Centos默认解析器时bash

shell脚本入门

#!/root/bash
echo "hello Word!!"

执行:

  • **方式一:**采用bash或sh+脚本的相对路径或绝对路径(不用赋予脚本+x权限)
  • **方式二:**采用输入脚本的绝对路径或相对路径执行脚本(必须具有可执行权限+x)

变量

  • 系统变量:使用工具查看所属位置

    H O M E 、 HOME、 HOMEPWD、 S H E L L 、 SHELL、 SHELLUSER等

  • 自定义变量

    • 定义变量 变量名=变量值。注:定义变量不能有空格,做特殊处理,一切皆字符串

    • 撤销变量 unset 变量名

    • 静态变量 readonly D=10 注:不能直接更改,也不能直接撤销,除非直接重新加载

    • 变量如果有空格,需要使用单引号或双引号

    • 提升全局变量,使用export,可以让其他shell使用

      [root@pier shells]# export B
      [root@pier shells]# ./helloworld.sh
      helloworld
      10
      
    • 变量规则: 和Java类似 环境变量名建议大写

    单引号双引号,基本上类似于编程语言中的引用字符串

    区别在于单引号’ '内剥夺所有字符的特殊含义,所有字符都是单纯的字符串而没有特殊功能,比如$取参数等命令都是无效的

    而双引号" "中除了字符串,特殊字符是没有被转义的,$等特殊字符一样可以使用其功能。

    反引号``是命令替换,通常用于把命令输出结果传给入变量中,类似变量后$=(命令)如:

  • 特殊变量

    • $n (功能描述,n为数字,%0代表该脚本名称,$1- 9 代 表 第 一 到 第 九 个 参 数 , 十 以 上 的 参 数 需 要 用 大 括 号 包 含 , 如 9代表第一到第九个参数,十以上的参数需要用大括号包含,如 910)
      • 例:
        vim param.sh
    #!/bin/bash
    echo '=============$n============'
    
    echo $0
    
    echo $1
    echo $2
    
    :wq
    

    执行

    [root@pier shells]# ./param.sh a b
    =============$n============
    ./param.sh
    a
    b
    
    • $# 打印执行脚本时传入变量的个数
    • $* / $@ 打印传入变量
    • $? 判断上一次命令是否正确0为true 非0为false

运算符

加上(())或者[]就可以正常运行了

条件判断

基础语法

  • test condition

    [ condition ](注意判别式前后一定要有空格)

常用判断条件

  • 1、两个整数之间的判断
比较符号来源记忆
大于-gtgreater than
大于等于-gegrreater equal
小于-ltless than
小于等于-leless equal
等于-eqequal
不等于-nenot equal

实操:

判断2和3的大小:

[root@pier shells]# [ 2 -gt 3 ]
[root@pier shells]# echo $?
1
[root@pier shells]# [ 2 -lt 3 ]
[root@pier shells]# echo $?
0
  • 2、字符串之间的比较
    • ==

实操,判断字符串s="== n = = " 和 s 1 = ′ = = n=="和s1='== n=="s1===n=='是否一致

[root@pier shells]# s="==$n=="
[root@pier shells]# s1='==$n=='
[root@pier shells]# [ s1==s ]
[root@pier shells]# echo $?
0
[root@pier shells]# echo '==$n=='
==$n==
[root@pier shells]# echo "==$n=="
====

这里就让我不解了,于是,我们找找为什么会出现相同的呢?

我貌似有一点点的傻,这个参数,在赋值的时候,仅仅是一个字符串,我们在判断的时候,也只是判断这两个字符串是否一样,二并没有去执行,因此,在下面的echo输出结果不一致,二在比较s和s1两个字符串是判断为正确。

  • 3、按照文件权限进行判断
    • -r 有读的权限(read)
    • -w 有写的权限(write)
    • -x 有执行的权限 (execute)

实操:

[root@pier shells]# test -x 200 
[root@pier shells]# echo $?
1
[root@pier shells]# ll
总用量 8
-rw-r--r--. 1 root root   0 1217 10:39 200
  • 4、按照文件类型进行判断
    • -f文件存在并且是一个常见的文件(file)
    • -e 文件存在(existence)
    • -d 文件存在并且是一个目录(directory)

实操:判断文件abc是否存在,abd呢?

[root@pier shells]# [ -e abc ]
[root@pier shells]# echo $?
0
[root@pier shells]# ll
总用量 8
-rw-r--r--. 1 root root   0 1217 10:39 200
drwxr-xr-x. 2 root root   6 1217 15:20 abc
-rwxr--r--. 1 root root  40 1217 09:40 helloworld.sh
-rwxrwxr--. 1 root root 151 1217 10:29 param.sh
[root@pier shells]# [ -e abd ]
[root@pier shells]# echo $?
1
  • 5、多重判断
    • || && 运算,和Java类似

实操:

[root@pier shells]# [ 100 -lt 200 ] && [ 100 -gt 50 ]
[root@pier shells]# echo $?
0
[root@pier shells]# [ 100 -lt 200 ] && [ 100 -lt 50 ]
[root@pier shells]# echo $?
1
[root@pier shells]# [ 100 -gt 200 ] && [ 100 -gt 50 ]
[root@pier shells]# echo $?
1
[root@pier shells]# [ 100 -gt 200 ] && [ 100 -gt 50 ]
[root@pier shells]# echo $?
1
[root@pier shells]# [ 100 -gt 200 ] || [ 100 -gt 50 ]
[root@pier shells]# echo $?
0

流程控制

流程控制的作用:
继续运行位在不同位置的一段指令(无条件分支指令)。
若特定条件成立时,运行一段指令,例如C语言的switch指令,是一种有条件分支指令。
运行一段指令若干次,直到特定条件成立为止,例如C语言的for指令,仍然可视为一种有条件分支指令。
运行位于不同位置的一段指令,但完成后会继续运行原来要运行的指令,包括子程序、协程(coroutine)及延续性(continuation)。
停止程序,不运行任何指令(无条件的终止)。

if判断

基本语法
#!/bin/bash

if [ condition1 ]#这是开始语句
then
 语句1
elif [ condition2 ]
then
 语句2 
 ·
 ·
 ·
else
 echo 语句n
fi#这是结束语句的标志

实例:

#!/bin/bash
#if测试脚本
if [ $1 -eq 1 ]
then
 echo "大数据,我来了!!!"
elif [ $1 -eq 2 ]
then
 echo "大数据,pier又回归!!!" 
else
 echo "都不留爷,pier要离开了!"
fi

执行:

[root@pier shells]# ./if.sh 2
大数据,pier又回归!!!
[root@pier shells]# vim if.sh 
[root@pier shells]# ./if.sh 2
大数据,pier又回归!!!
[root@pier shells]# ./if.sh 1
大数据,我来了!!!
[root@pier shells]# ./if.sh 3
都不留爷,pier要离开了!
[root@pier shells]# ./if.sh 
./if.sh: 第 3 行:[: -eq: 期待一元表达式
./if.sh: 第 6 行:[: -eq: 期待一元表达式
都不留爷,pier要离开了!

这里我们发现这个他居然有错误提示,于是发现了,报错的两行正好是我们需要传入参数的两行,所以,我们就可以在if判断外边再加一个判断参数不为空的函数就可以了。

if [ $# -lt 1 ]
then
        echo "请传参!"
exit
fi

case分支

#!/bin/bash

case $1 in
"1")
        echo "这是1分支! ! !"
;;#这个相当于break
"2")
        echo "这是2分支!!!"
;;

        echo "default结束了!!!"
;;
esac

for 循环

for(( 初始值;循环控制条件;变量变化 ))
do
	程序语句
done
注:在循环控制条件中使用><=这类符号,不识别-gt这类符号

注意点$@和$*的的区别:在打印时,不加双引号时都是循环调用,主要是注意在在输出"$*"时。是一次性拿进来所有的参数,而其他的情况,都是一次只拿一个参数。循环调用。

[root@pier shells]# ./for1.sh 刘亦菲 小阿七 Gai
==输出不加引号的$*==
你好美女--刘亦菲
你好美女--小阿七
你好美女--Gai
==输出不加引号的$@==
你好美女--刘亦菲
你好美女--小阿七
你好美女--Gai
==输出加引号的$*==
你好美女--刘亦菲 小阿七 Gai
==输出加引号的$@==
你好美女--刘亦菲
你好美女--小阿七
你好美女--Gai

while

while [ 条件判断式 ] 
  do 
    程序
  done

read读取控制台输入

read(选项)(参数)

选项:

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

-t :指定读取值等待的时间

参数:

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

实例:

[root@pier shells]# read -t 5 -p "请在五秒内输入名字:" NAME
请在五秒内输入名字:jiu
[root@pier shells]# echo $NAME
jiu

函数

系统函数

basename:获取路径的最后的文件名

dirname : 获取文件的上一层的绝对路径

[root@pier shells]# basename root/shells/
shellss
[root@pier shells]# dirname /root/shells/cash.sh 
/root/shells

自定义函数

基本语法

[function] funname[()]

	Action;#执行或计算的任务
	[return int;]

#调用函数
funname

定义函数:

使用1

#/bin/bash

#定义函数
total=0
function sum()
        total=$[$1+$2];
        #注意:这里返回的值不能超过0-255,
        #一旦操过,会返回对255取余的值
        return $total;


#read 输入参数

read -t 5 -p "请输入第一个数字:" n1
read -t 5 -p "请输入第二个数字:" n2
#调用函数
sum $n1 $n2

#输出结果
echo "sum=$?"

测试:

[root@pier shells]# ./fun.sh 
请输入第一个数字:2
请输入第二个数字:43
sum=45
[root@pier shells]# ./fun.sh 
请输入第一个数字:100
请输入第二个数字:500
sum=88

**小问题:**那我们输出的结果应该是600,但是是88是对256取余的结果。我们应该怎么解决呢?

我们既然知道了是return $total;的问题,那么我们便不要这一句,直接注释掉。再在最后的输出是,将输出的结果编程echo "sum=$total"就可以了。

[root@pier shells]# ./fun.sh 
请输入第一个数字:100
请输入第二个数字:500
sum=600

注:shell编程并不是很适合计算,因此我们尽量只在里面写逻辑关系,运算交给擅长的工具来。

Shell工具

cut

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

基本语法

  • cut [选项参数] filename

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

选项参数说明

选项参数功能
-f列号,提取第几列
-d分隔符,按照指定分隔符分割列
-c指定具体的字符

案例

  • 1)数据准备
[root@pier shells]$ cat cut.txt
dong shen
guan zhen
wo  wo
lai  lai
le  le
  • 2)切割cut.txt第一列
[root@pier shells]$ cut -d " " -f 1 cut.txt 
dong
guan
wo
lai
le
  • 3)切割cut.txt第二、三列
[root@pier shells]$ cut -d " " -f 2,3 cut.txt 
shen
zhen
wo
lai
le
  • 4)在cut.txt文件中切割出guan
[root@pier shells]$ cat cut.txt | grep "guan" | cut -d " " -f 1
guan
  • 5)选取系统PATH变量值,第2个“:”开始后的所有路径:
[root@pier shells]$ echo $PATH
/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/atguigu/bin
[root@pier shells]$ echo $PATH | cut -d: -f 2-
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/atguigu/bin
  • 6)切割每一行的第一个字母(这里中文也是一个字符)
[root@pier shells]# cut -c 1 cut.txt 
d
g
w
l
l
  • 7)切割ifconfig 后打印的IP地址
[root@pier shells]# ifconfig | grep netmask | awk -F "inet " 'print $2' | awk -F " " 'print $1'
192.168.40.100
127.0.0.1
192.168.122.1

awk

概述

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

基本用法

awk [选项参数] ‘pattern1action1 pattern2action2…’ filename

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

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

选项参数说明

选项参数功能
-F指定输入文件折分隔符
-v赋值一个用户定义变量

案例

(1)数据准备

[root@pier shells]$ sudo cp /etc/passwd ./

(2)搜索passwd文件以root关键字开头的所有行,并输出该行的第7列。

[root@pier shells]$ awk -F: '/^root/print $7' passwd 
/bin/bash

(3)搜索passwd文件以root关键字开头的所有行,并输出该行的第1列和第7列,中间以“,”号分割。

[root@pier shells]$ awk -F: '/^root/print $1","$7' passwd 
root,/bin/bash

注意:只有匹配了pattern的行才会执行action

(4)只显示/etc/passwd的第一列和第七列,以逗号分割,且在所有行前面添加列名user,shell在最后一行添加"dahaige,/bin/zuishuai"。

[root@pier shells]$ awk -F : 'BEGINprint "user, shell" print $1","$7 ENDprint "dahaige,/bin/zuishuai"' passwd
user, shell
root,/bin/bash
bin,/sbin/nologin
。。。
atguigu,/bin/bash
dahaige,/bin/zuishuai

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

(5)将passwd文件中的用户id增加数值1并输出

[root@pier shells]$ awk -v i=1 -F: 'print $3+i' passwd
1
2
3
4

awk的内置变量

变量说明
FILENAME文件名
NR已读的记录数(行数)
NF浏览记录的域的个数(切割后,列的个数)

案例:

  1. 统计passwd文件名,每行的行号,每行的列数
[root@pier shells]# awk -F: 'print "filename:"  FILENAME ", 行号:" NR  ",列号:" NF' passwd 
filename:passwd, 行号:1,列号:7
filename:passwd, 行号:2,列号:7
filename:passwd, 行号:3,列号:7
filename:passwd, 行号:4,列号:7

2)切割IP

[root@pier shells]# ifconfig | grep netmask | awk -F "inet " 'print $2' | awk -F " " 'print $1'
192.168.40.100
127.0.0.1
192.168.122.1

sort

sort命令是在Linux里非常有用,它将文件进行排序,并将排序结果标准输出。

1)基本语法

sort(选项)(参数)

选项说明
-n依照数值的大小排序
-r以相反的顺序来排序
-t设置排序时所用的分隔字符
-k指定需要排序的列

参数:指定待排序的文件列表

2)案例实操

(1)数据准备

[root@pier shells]$ touch sort.sh
[root@pier shells]$ vim sort.sh 
bb:40:5.4
bd:20:4.2
xz:50:2.3
cls:10:3.5
ss:30:1.6

(2)按照“:”分割后的第三列倒序排序。

[root@pier shells]$ sort -t : -nrk 3 sort.sh 
bb:40:5.4
bd:20:4.2
cls:10:3.5
xz:50:2.3
ss:30:1.6

正则表达式

含义:

正则表达式是用于描述字符排列和匹配模式的一种语法规则. 它主要用于字符串的模式分割、匹配、查找及替换操作.

特殊使用

注:这里我们学习前找一份文件,做测试。没有用文件的小伙伴,可以学我,cp /etc/passwd ./,复制过来一份,但是不要去修改源文件,万一。。。嗯,就哦豁!

  • 正则表达式用来在文件中匹配符合条件的字符串,正则是包含匹配。grep、awk、sed 等命令可以支持正则表达式。
  • 通配符用来匹配符合条件的文件名,通配符是完全匹配。ls、find、cp 这些命令不支持正则表达式,所以只能使用 shell 自己的通配符来进行匹配了。

^匹配以什么什么字符开头的一行cat passwd | grep ^a

* 匹 配 以 什 么 什 么 字 符 结 尾 的 一 行 ∗ : ‘ c a t p a s s w d ∣ g r e p t 匹配以什么什么字符结尾的一行*:`cat passwd | grep t catpasswdgrept`

匹配空行就可以这么写了^t$

.匹配任意一个字符:cat passwd | grep r..t注:这就是匹配r和t之间相隔两个字符的句子,中间又几个点就代表相隔字符。

*不单独使用,和他左边的第一个字符连用,表示匹配上一个字符0次或者多次cat passwd | grep ro*t这个就会匹配到只要包含rt,或者rt之间仅有o字符的的所有单词所在的那一行。

特殊字符[]:

  • 表示匹配某个范围内的一个字符,例如

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

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

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

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

  • [root@pier shells]$ cat /etc/passwd | grep r[a,b,c]*t

案例
匹配所有包含n或者包含c的句子。

[root@pier shells]# cat if.sh | grep [n,c] 
#!/bin/bash
then
	echo "请传参!"
then 
 echo "大数据,我来了!!!"
then 
 echo "大数据,pier又回归!!!" 
 echo "都不留爷,pier要离开了!"

特殊字符:
有些特殊字符又特殊含义,所以在使用时需要加\\才可以正常的使用。并使用单引号引起来。

注意:shell编程虽然不难,也许一天就吃了个七七八八,但是也得要多加练习呀,一起加油呀,学会了,就等待着和pier一起进入快乐的Hadoop吧!

以上是关于shell编程的主要内容,如果未能解决你的问题,请参考以下文章

代码片段:Shell脚本实现重复执行和多进程

Linux bash基础特性二

VSCode自定义代码片段——JS中的面向对象编程

VSCode自定义代码片段9——JS中的面向对象编程

使用 Pygments 检测代码片段的编程语言

面向面试编程代码片段之GC