Shell Script
概述
Shell是命令行解释器,它接受应用程序或用户命令,然后调用操作系统内核。
Shell可以嵌套
- 使用
exit
命令可以退出当前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
-
#!/bin/sh echo "Hello Shell!"
Linux下面用命令如何运行.sh文件的方法
- 直接./加上文件名.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
命令查看所有全局变量printenv <variable>
:打印指定的全局变量
echo $<variable>
,echo命令配合$符也可以打印变量。set
运行不带选项或参数的命令会输出所有设置的列表——所有 shell 变量和函数的名称和值。- shell里直接打印不存在的变量并不会报错,而是输出空。
用户自定义变量
基本语法
- 定义变量:
<variable>=<value>
=
号前后不能有空格,在shell中无需指定变量类型。- 有空格的情况可以使用引号,例如
variable="Hello variable"
。 - 属于局部变量,子shell不可见。
- 导出变量
- 自定义的变量默认局部变量,但是可以通过
export
语句导出为全局变量。 - 语法:
export <variable>
- 自定义的变量默认局部变量,但是可以通过
- 修改变量
- 修改变量值只对变量所在的shell及子shell生效,也就是说子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
使用readonly
关键字可以让变量只读
-
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
撤销指定变量
- 使用
unset <variable>
,即可撤销指定变量。 - readonly变量无法撤销。
特殊变量
PATH
。对应当前配置的环境变量。
-
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> ]
,虽然也是中括号,但不同于前面的是,要求前后都留有空格。
-
条件非空即为true,例如。
-
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$ if ((1 > 2)); then echo YES; else echo NO; fi NO
判断文件是否有对应权限
断言符
-r
:读,read。-w
:写,write。-x
:执行,execute。
示例
-
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
按照文件类型进行判断
断言符
-e
:文件存在,existence。-f
:文件存在且为常规文件,file。-d
:文件存在且为目录,directory。
连接符
&&
表示上条命令执行成功时,执行下条命令;||
表示上条命令执行失败后,执行下条命令;
示例:
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 判断
单分支,有两种写法。
-
if [ <condition> ]; then #code…… fi
-
if [ <condition> ] then #code…… fi
表达式可以使用连接符,下面是例子
-
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
另外还支持在括号内使用-a
、-o
来表示and、or。
-
xuegao@LAPTOP-XUEGAO:~/temp/script$ if [ $a -gt 18 -a $a -lt 36 ]; then echo OK; fi OK
多分支使用elif
、else
来实现,下面是示例。
-
#!/bin/sh if [ $1 -lt 18 ] then echo "未成年人" elif [ $1 -lt 35 ] then echo "青年人" elif [ $1 -lt 60 ] then echo "中年人" else echo "老年人" fi
case 语句
语法
-
case $var in <value1>) #code ;; <value2>) #code ;; *) #default code esac
示例
-
#!/bin/sh case $1 in 1) echo "one" ;; 2) echo "two" ;; 3) echo "three" ;; *) echo "other figures" ;; esac
for 循环
((;;))
方式
语法
-
for (( <initial value>;<cycle control coditions>;<change variables> )) do #code done
示例
-
#!/bin/bash sum=0 for ((i=1;i<=$1;i++)) do sum=$[$sum+$i] done echo $sum
for i in xx xx
方式
语法(item array表元素数组)
-
fro <variable> in <element array> do #code d
示例
-
for os in linux windwos macos; do echo $os; done linux windwos macos
另外,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 循环
语法
-
while [ <condition> ] do #code done
示例
-
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
关键字可以让写法优雅许多。
let
是 Bash 的内置函数,它允许我们进行简单的算术运算。语法是let <arithmetic expression>
。
下面是使用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>
- optional
-p
指定读取值时的提示符;-t
指定读取值时等待的时间(秒),若不指定表示无限等待;
- parameter
- 指定读取值对应的变量
- optional
示例
-
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>
。
功能
- basename命令会删除所有的前缀,以及最后的
/
符,最后打印结果。 - 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
语法:dirname <pathname>
功能:去掉文件名,获取路径。
示例(获取绝对路径)
-
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
自定义函数
语法
-
<function> functionName(){ #action; [return int;] }
注意
- 必须先声明函数和,才能调用。因为shell是逐行运行。
- 函数返回值通过
$?
获取,函数通过return显式返回,或使用最后一条命令的运行结果。如果使用return的话,返回值要求为0~255。
示例
-
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
归档文件
需求场景
- 写个每天对指定目录归档备份的脚本,并将归档日期作为文件名后缀,文件归档到~/temp/archive。
脚本
-
#!/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
使用crontab管理定时任务
-
0 2 * * * /home/xuegao/dev/workspace/script/shell/dailyArchive.sh /home/xuegao/temp/archive
正则
常规匹配
在Linux中,grep、sed、awk等文本处理工具,都支持通过正则表达式进行模式匹配。
匹配文本,例如下面匹配DIR_NAME
字符串。
-
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"
小技巧
- 连用
^$
可以匹配空行,使用grep -n ^$
可以匹配空行并显示行号。 - 连用
.*
匹配任意字符任意次
常用特殊字符
字符区间。[]
:表示某个范围内的一个字符。
[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
cut
的工作就是剪切,负责剪切文件数据。
语法
cut <optional parameter> <filename>
- 可选参数
-f
:列号,提取第几列。-d
:分隔符,按照指定分隔符分割列,默认为制表符\t
-c
:按字符进行切割,后加n表示取第几列。
按空格分隔示例
-
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$
-f
参数支持同时提取多列
-
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>
- 根据正则表达式,从input-file获取文本,并以此执行action。action里执行代码。
awk <options> '/<regular expression>/ {<action>}' <input-file> > <output-file>
- 同上,并输出结果到output-file。
- options参数
-F
:指定文件分隔符v
:赋值一个用户自定义变量
示例
-
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
内置变量
- FILENAME:文件名
- NR:已读的记录数(行号)
- NF:浏览记录的域个数(切割后,列的个数)
内置变量使用示例
-
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