Shell Script
概述
Shell是命令行解释器,它接受应用程序或用户命令,然后调用操作系统内核。
Shell 脚本(shell script)是种为 shell 编写的脚本程序。常说的shell通常都是指 shell 脚本,但shell和shell script是两个不同的概念。通常说“shell编程”都是指 shell 脚本编程,不是指开发 shell 自身。
-
sh(Bourne Shell)是个早期的重要shell,1978年由史蒂夫·伯恩编写,并同Version 7 Unix一起发布。
-
bash(Bourne-Again Shell)是为GNU计划编写的Unix shell。1987年由布莱恩·福克斯创造。主要目标是与POSIX标准保持一致,同时兼顾对sh的兼容,是各种Linux发行版标准配置的Shell,在Linux系统上/bin/sh往往是指向/bin/bash的符号链接。
-
dash (Debian Almquist shell)一种 Unix shell。它比 Bash 小,只需要较少的磁盘空间,但是它的对话性功能也较少。它由 NetBSD版本的Almquist shell (ash)发展而来,于1997年由赫伯特·许(Herbert Xu)移植到Linux上,于2002年改名为 dash。
脚本以#!/bin/sh
、#!/bin/bash
或#!/bin/dash
开头,用于指定解析器。
来写个Hello Shell
- 直接./加上文件名.sh,如运行hello.sh为./hello.sh【hello.sh必须有x权限,即执行权限】
- 直接
sh
或bash
加上文件名,如运行hello.sh为sh hello.sh【hello.sh无需x权限,即执行权限】 source
或者.
(简写),都能实现和sh
一样的效果。但不同点在于,前面的方式会创建子shell(启动了个sh进程),在子shell里执行命令,而source
方式直接在当前shell执行。
变量
系统预设变量
前面提到子shell的存在,使不使用的区别就在于环境变量的继承关系。在子shell设置的当前变量,父shell是不可见的。
常用系统变量:HOME、PWD、SHELL、USER
- 全局变量在本shell及所有子shell可见(父shell不可见),局部变量只在当前shell可见。
env
、printenv
命令查看所有全局变量echo $<variable>
,echo命令配合$符也可以打印变量。set
运行不带选项或参数的命令会输出所有设置的列表——所有 shell 变量和函数的名称和值。- shell里直接打印不存在的变量并不会报错,而是输出空。
用户自定义变量
深入学习变量
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ numberX=1+5 xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $numberX 1+5
使用$((<expression>))
或$[<expression>]
,括号里放表达式。
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ numberY=$((6+6)) xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $numberY 12 xuegao@xuegao-PC:~/dev/workspace/script/shell$ numberU=$[9+9] xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $numberU 18
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ readonly readonlyX="Hello readonly" xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $readonlyX Hello readonly xuegao@xuegao-PC:~/dev/workspace/script/shell$ readonlyX="Change test" bash: readonlyX: readonly variable
撤销指定变量
特殊变量
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $PATH /home/xuegao/.config/nvm/versions/node/v18.14.0/bin:/usr/local/app/maven/apache-maven-3.6.3/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/sbin:/usr/sbin:/snap/bin:/usr/local/app/hadoop-3.3.2/bin:/opt/app/kafka/kafka_2.13-3.1.0/bin
-
可以看到除了系统的
bin
、sbin
这些,还有node、maven、hadoop等环境变量,这都是我自己配置在该机器的,将路径添加到环境变量后,可以直接执行该路径下的可执行文件——在任何地方。就像下面查看nodejs版本一样。 -
xuegao@xuegao-PC:~/dev/workspace/script/shell$ node -v v18.14.0
$<number>
。number为数字,$0
表示当前脚本名称(绝对路径),$1 ~ $9
代表一到九个参数,十以上的参数需要用大括号包含${<number>}
,例如$<11>
。
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ cat helloShell.sh #!/bin/sh echo "这里是$0脚本" echo "Hello $1" xuegao@xuegao-PC:~/dev/workspace/script/shell$ ./helloShell.sh 参数一 这里是./helloShell.sh脚本 Hello 参数一
$#
。获取所有输入参数个数,常用于循环判断参数的个数是否正确,以及加强脚本的健壮性。
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ cat paramater.sh #!/bin/sh echo script name: $0 echo 1st paramater: $1 echo 2st paramater: $2 echo parameter numbers: $# xuegao@xuegao-PC:~/dev/workspace/script/shell$ sh paramater.sh a b script name: paramater.sh 1st paramater: a 2st paramater: b parameter numbers: 2
$*
、$@
。两者都是代表命令行中所有的参数,不过$*
是字符串,$@
是实际的数组。若不加双引号,两者是一样的。
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ cat paramater.sh #!/bin/sh echo script name: $0 echo 1st paramater: $1 echo 2st paramater: $2 echo parameter numbers: $# echo $* echo $@ xuegao@xuegao-PC:~/dev/workspace/script/shell$ sh paramater.sh a b script name: paramater.sh 1st paramater: a 2st paramater: b parameter numbers: 2 a b a b
$?
。最后一次执行的命令的返回状态。若值为0,表正确执行了;若不为0(具体是啥,由命令自己决定),则证明上个命令执行不正确;
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ ls helloShell.sh paramater.sh xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $? 0 xuegao@xuegao-PC:~/dev/workspace/script/shell$ fajefpewi -bash: fajefpewi: command not found xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $? 127
运算符
使用expr
关键字可以实现计算功能,要注意参数之间用空格隔开,否则会被视为字符串。另外,像*
号由于默认视为通配符,所以要使用表示视其为普通的
*
号。
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ expr 5 + 5 10 xuegao@xuegao-PC:~/dev/workspace/script/shell$ expr 5 * 5 25
前面提到过使用[]
或者(())
的方式实现运算,只要把表达式放到里面就好了。
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $[6 / 2] 3
赋值。下面分别展示两者运算后的赋值方法。$(<command>)
实现命令替换功能,执行内部的command,然后输出到指定位置。
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ var_a=$((6*6)) xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $var_a 36 xuegao@xuegao-PC:~/dev/workspace/script/shell$ var_b=$(expr 4 - 5) xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $var_b -1 xuegao@xuegao-PC:~/dev/workspace/script/shell$ var_c=`expr 5 + 6` xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $var_c 11
写个加法脚本
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ cat add.sh #!/bin/sh sum=$(($1+$2)) echo sum=$sum xuegao@xuegao-PC:~/dev/workspace/script/shell$ ./add.sh 34 43 sum=77
条件判断
判断状态
使用test
关键字,语法为test <condition>
,下面是示例,使用$?
获取语句执行状态(0
表true
)。
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $var_a hello xuegao@xuegao-PC:~/dev/workspace/script/shell$ test $var_a = HELLO xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $? 1 xuegao@xuegao-PC:~/dev/workspace/script/shell$ test $var_a = hello xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $? 0
使用[ <condition> ]
,虽然也是中括号,但不同于前面的是,要求前后都留有空格。
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ [ hello ] xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $? 0 xuegao@xuegao-PC:~/dev/workspace/script/shell$ [ ] xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $? 1
常用判断条件
比较符
-eq
:等于,equal。-ne
:不等于,not equal。-lt
:小于,less than。-le
:小于等于,less equal。-gt
:大于,greater than。-ge
:大于等于,greater equal。
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ [ 4 -ge 4 ] xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $? 0
注意如果使用(())
语法,那么括号内是可以直接使用<
、>
、=
符号的。
断言符
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ ll total 12 -rwxr-xr-x 1 xuegao xuegao 39 Mar 7 00:07 add.sh -rwxr-xr-x 1 xuegao xuegao 51 Mar 6 01:13 helloShell.sh -rw-r--r-- 1 xuegao xuegao 120 Mar 7 00:03 paramater.sh xuegao@xuegao-PC:~/dev/workspace/script/shell$ [ -x paramater.sh ] xuegao@xuegao-PC:~/dev/workspace/script/shell$ echo $? 1
断言符
连接符
&&
表示上条命令执行成功时,执行下条命令;||
表示上条命令执行失败后,执行下条命令;
示例:
xuegao@xuegao-PC:~/dev/workspace/script/shell$ ls
add.sh helloShell.sh paramater.sh
xuegao@xuegao-PC:~/dev/workspace/script/shell$ test -f add.sh && echo OK
OK
xuegao@xuegao-PC:~/dev/workspace/script/shell$ test -f addddd.sh && echo OK
xuegao@xuegao-PC:~/dev/workspace/script/shell$ test -f addddd.sh && echo OK || echo failer
failer
流程控制
if 判断
-
xuegao@LAPTOP-XUEGAO:~/temp/script$ echo $a 23 xuegao@LAPTOP-XUEGAO:~/temp/script$ if [ $a -gt 18 ] && [ $a -lt 36 ]; then echo OK; fi OK
-
#!/bin/sh if [ $1 -lt 18 ] then echo "未成年人" elif [ $1 -lt 35 ] then echo "青年人" elif [ $1 -lt 60 ] then echo "中年人" else echo "老年人" fi
case 语句
语法
示例
-
#!/bin/sh case $1 in 1) echo "one" ;; 2) echo "two" ;; 3) echo "three" ;; *) echo "other figures" ;; esac
for 循环
((;;))
方式
语法
示例
示例
另外,shell支持{n..m}
这种语法,下面是例子。{1..100}
表示从1到100的数组,所以下面的for循环会执行一百次。
-
xuegao@xuegao-PC:~/dev/workspace/script$ for i in {1..100}; do sum=$[$sum+$i]; done; echo $sum 5050
前面特殊变量章节提到过$@*、
$@`,它俩也可以作为数组供给for循环使用。当加上双引号时,表现会所有不同。
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ cat forIn.sh #!/bin/bash echo '$*============================' for param in "$*" do echo $param done echo '$@============================' for param in "$@" do echo $param done xuegao@xuegao-PC:~/dev/workspace/script/shell$ ./forIn.sh a b c $*============================ a b c $@============================ a b c
while 循环
语法
示例
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ cat while.sh #!/bin/bash a=1 sum=0 while [ $a -le $1 ] do sum=$[ $sum + $a ] a=$[ $a + 1 ] done echo $sum xuegao@xuegao-PC:~/dev/workspace/script/shell$ ./while.sh 100 5050
这种夹杂着$和中括号的写法实在是太丑陋了,但使用let
关键字可以让写法优雅许多。
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ cat whileLet.sh #!/bin/bash a=1 sum=0 while [ $a -le $1 ] do let sum+=a let a++ done echo $sum xuegao@xuegao-PC:~/dev/workspace/script/shell$ ./whileLet.sh 100 5050
读取console输入
语法
read <optional> <parameter>
示例
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ cat read.sh #!/bin/bash read -t 30 -p "你的称呼是:" name echo "欢迎$name使用本程序" xuegao@xuegao-PC:~/dev/workspace/script/shell$ bash read.sh 你的称呼是:雪糕 欢迎雪糕使用本程序
函数
系统函数
basename
语法:basename <pathname> <suffix>
。
功能
示例
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ basename ~/dev/workspace/script/shell/add.sh add.sh xuegao@xuegao-PC:~/dev/workspace/script/shell$ basename ~/dev/workspace/script/shell/add.sh .sh add
dirname
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ cat dirname.sh #!/bin/bash cd $(dirname $0) echo $(pwd) xuegao@xuegao-PC:~/temp$ bash ../dev/workspace/script/shell/dirname.sh /home/xuegao/dev/workspace/script/shell
自定义函数
语法
注意
示例
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ cat functionTest.sh #!/bin/bash function add(){ sum=$[$1 + $2] echo $sum } read -p "输入整数a:" a read -p "输入整数b:" b result=$(add a b) echo 求和结果为:$result echo 和的平方:$[ $result * $result ] xuegao@xuegao-PC:~/dev/workspace/script/shell$ ./functionTest.sh 输入整数a:12 输入整数b:34 求和结果为:46 和的平方:2116
归档文件
脚本
-
#!/bin/bash #判断参数个数是否为1 if [ $# -ne 1 ] then echo 参数数量不为一个 exit fi #判断是否为目录 if [ -d $1 ] then echo else 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=~/temp/archive/$FILE #归档文件 echo 开始归档…… tar -czf $DEST $DIR_PATH/$DIR_NAME if [ $? -eq 0 ] then echo 归档成功 echo 归档文件名为:$DEST else echo 归档出错 fi exit
正则
常规匹配
在Linux中,grep、sed、awk等文本处理工具,都支持通过正则表达式进行模式匹配。
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ cat dailyArchive.sh | grep DIR_NAME DIR_NAME=$(basename $1) FILE=archive_${DIR_NAME}_${DATE}.tar.gz tar -czf $DEST $DIR_PATH/$DIR_NAME
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ cat dailyArchive.sh | grep ^if if [ $# -ne 1 ] if [ -d $1 ] if [ $? -eq 0 ]
-
if [ $? -eq 0 ] xuegao@xuegao-PC:~/dev/workspace/script/shell$ cat dailyArchive.sh | grep gz$ FILE=archive_${DIR_NAME}_${DATE}.tar.gz
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ cat dailyArchive.sh | grep arch..e FILE=archive_${DIR_NAME}_${DATE}.tar.gz DEST=~/temp/archive/$FILE
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ cat helloShell.sh | grep Hel* echo "Hello $1"
小技巧
常用特殊字符
[6,8]
:匹配6或8(逗号可省略)[0-9]
:匹配一个0至9的数字[0-9]*
:任意长度的数字[a-z]
:匹配一个a到z的字母[a-z]*
:匹配任意长度的字母[a-c,e-f]
:匹配a到c,或者e至f之间的一个字符。
特殊字符使用避免被转义,要注意使用
的话,必须要将匹配文本使用引号包裹起来。下面是示例如何匹配$。
-
xuegao@xuegao-PC:~/dev/workspace/script/shell$ cat dailyArchive.sh | grep "$1" if [ -d $1 ] DIR_NAME=$(basename $1) DIR_PATH=$(cd $(dirname $1); pwd)
下面是个匹配国内手机号的示例,其中grep
添加-E
参数表示支持regular expression扩展语法。({9}
就是扩展语法,表示前面的规则重复9次)
-
echo "13899889988" | grep -E ^1[3456789][0-9]{9}$
文本处理工具
cut
语法
按空格分隔示例
-
xuegao@xuegao-PC:~/dev/workspace/script/text$ cat state.txt Andhra Pradesh Arunachal Pradesh xuegao@xuegao-PC:~/dev/workspace/script/text$ cut -d " " -f 1 state.txt Andhra Arunachal xuegao@xuegao-PC:~/dev/workspace/script/text$
-
xuegao@xuegao-PC:~/dev/workspace/script/text$ cat note.txt 14 1 Lombok 15 1 Jackson xuegao@xuegao-PC:~/dev/workspace/script/text$ cut -f 1,3 note.txt 14 Lombok 15 Jackson
-f
参数还支持-
语法
-
xuegao@xuegao-PC:~/dev/workspace/script/text$ cut -f -2 note.txt 14 1 15 1 xuegao@xuegao-PC:~/dev/workspace/script/text$ cut -f 2- note.txt 1 Lombok 1 Jackson
awk
常规使用
强大的文本分析工具,逐行读入,默认以空格为分隔符进行切片,再进行分析处理。
语法
awk <options> '/<regular expression>/ {<action>}' <input-file>
awk <options> '/<regular expression>/ {<action>}' <input-file> > <output-file>
- options参数
示例
-
xuegao@xuegao-PC:~/dev/workspace/script/text$ cat employee.txt ajay manager account 45000 sunil clerk account 25000 varun manager sales 50000 amit manager account 47000 tarun peon sales 15000 deepak clerk sales 23000 sunil peon sales 13000 satvik director purchase 80000 xuegao@xuegao-PC:~/dev/workspace/script/text$ awk '/sa..s/ {print $1","$2}' employee.txt varun,manager tarun,peon deepak,clerk sunil,peon
拓展:BEGIN再所有数据读取之前执行,END在所有数据执行之后执行。
-
xuegao@xuegao-PC:~/dev/workspace/script/text$ cat employee.txt | awk 'BEGIN{print "开始"} {print $1","$2} END{print "结束"}' 开始 ajay,manager sunil,clerk varun,manager amit,manager tarun,peon deepak,clerk sunil,peon satvik,director 结束
变量
使用-v
参数
-
xuegao@xuegao-PC:~/dev/workspace/script/text$ awk -v i=1 '/sa..s/ {print $1,$2,i}' employee.txt varun manager 1 tarun peon 1 deepak clerk 1 sunil peon 1
内置变量
内置变量使用示例
-
xuegao@xuegao-PC:~/dev/workspace/script/text$ awk '/sa..s/ {print "文件名:"FILENAME ",行号:"NR ",列数:"NF}' employee.txt 文件名:employee.txt,行号:3,列数:4 文件名:employee.txt,行号:5,列数:4 文件名:employee.txt,行号:6,列数:4 文件名:employee.txt,行号:7,列数:4
综合应用案例
发送消息
利用Linux自带的mesg和write工具,向其他用户发送消息。
脚本
-
#!/bin/bash #截取用户信息 loginUser=$(who | grep -i -m 1 $1 | awk '{print $1}') #-z用于判断字符串是否为空 if [ -z $loginUser ] then echo "$1 不在线" echo "退出当前脚本" exit fi #判断是否开启了mesg allowed=$(who -T | grep -i -m 1 $1 | awk '{print $2}') if [ $allowed != "+" ] then echo "$1 没有开启消息功能" echo "退出当前脚本" exit fi #确认是否有消息发送 if [ -z $2 ] then echo "没有可发送的消息" echo "退出当前脚本" exit fi #获取消息 wholeMessage=$(echo $* | cut -d " " -f 2-) #获取终端 userTerminal=$(who | grep -i -m 1 $1 | awk '{print $2}') #发送消息 echo $wholeMessage | write $loginUser $userTerminal echo $wholeMessage echo $loginUser echo $userTerminal if [ $? -eq 0 ] then echo "发送成功" else echo "发送失败" fi exit
原文地址:https://blog.csdn.net/liangfenxuegao/article/details/129630923
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_25402.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!