Shell脚本中获取命令运行结果、特殊变量使用、条件判断等常用操作
2020-07-11 00:49
148 查看
文章目录
前言
最近在处理一个
Python局部变量的作用域问题时发现有些奇怪,想起了之前常写的
Lua脚本,于是想写个函数测试一下,结果发现短短的十几行代码出现了多个错误,这可是我写了近三年的代码啊,才放下半年就记不清了,所以知识这个东西还是要不断“温故”,今天要总结的
Shell脚本命令也是,基本属于一看就会,一写不对的状态,所以还是要把常用的操作总结到一起,方便查找和复习。
获取命令执行结果
脚本中常常要获取一些命令的执行结果,比如当前目录
pwd、当前时间
date等等,如果在控制台时直接输入后回车就能看到结果,但是在
Shell脚本中却不能这样做,常见的有以下两种方式。
使用反引号 `
command `
来执行命令
反引号就是键盘上
Tab键上方的那个按键对应的符号,常写 Markdown 的小伙伴知道这个符号就是包裹代码块的那个符号,在
Shell脚本中被用来执行命令得到结果,举个简单的例子
#!/bin/bash result=date echo $result result=`date` echo $result
将上述命令保存到文件
cmd.sh中运行
./cmd.sh得到结果:
$ ./cmd.sh date Tue Jul 7 23:48:03 CST 2020
从运行结果可以看出,如果不加反引号,我们常用的这些命令会被当成普通的字符串处理。
使用括号组合 $(command) 来执行命令
除了上面的反引号,使用美元符和小括号组合也可以在 Shell 脚本中运行命令,使用同样的例子测试
#!/bin/bash result=`date` echo $result result=$(date) echo $result
保存到文件
cmd.sh中运行
./cmd.sh得到结果:
$ ./cmd.sh Tue Jul 7 23:53:27 CST 2020 Tue Jul 7 23:53:27 CST 2020
对比可以看出两种方式在这个命令下运行结果是一样的。
两种方式的区别
虽然上述两种方式都可以在
Shell脚本中得到命令运行的结果,但是有一点是不一样的,那就是反引号执行命令不支持嵌套,不能实现反引号中再出现反引号,而
$(command)的方式是支持嵌套的,关于这一点可以看下面这个例子。
$ echo $(ls $(pwd)) cmd.sh
分析一下这个命令
echo $(ls $(pwd)),最里面的命令是
$(pwd)先执行得到当前目录,然后执行命令
$(ls 当前目录)得到目录下的文件,再通过
echo命令把这个结果输出,就得到了
cmd.sh这个文件名,因为我这个目录下只有这一个文件。
系统的命令使用反引号的方式改写就不生效了。
$ echo `ls `pwd`` cmd.shpwd
我们还是仿照上面嵌套来写,但是
echo后面的内容其实被分成了3部分,一个
ls命令,一个
pwd字符串、一个空命令,这样就能解释运行结果
cmd.shpwd了。
对照着结果我们就可以知道了,
$(command)的方式更加强大,可以支持命令的嵌套,应用更广泛一点,而反引号的方式跟多出现在之前的脚本中。
特殊变量使用
从学习语言的第一天起就记住了变量名中只能有数字、字母、下划线,并且数字不能打头(Shell中只能字母开头),但是在
Shell脚本中有一些特殊的变量,包含各种奇奇怪怪的符号。
$0 $1 $2 …
这些是运行
Shell脚本时传递给脚本的命令行参数。命令行参数用 $n 表示,$0表示当前脚本的文件名,$1 表示第一个参数,$2 表示第二个参数,依次类推,可以类比 Windows 下的
%0、
%1、
%2…
$$
当前
Shell脚本的进程ID。如果在命令行执行得到的是当前
bash的进程ID,如果放到脚本中,得到的是脚本的进程ID。
$?
可以获取上一个命令执行后的返回结果。
$#
传递给脚本的命令行参数的个数。
$*
传递给脚本的命令行参数的所有参数。
$@
传递给脚本的命令行参数的所有参数,与
$*稍有不同。
测试
写个脚本测试一下,新建
cmdargs.sh文件,编写下面代码:
#!/bin/bash echo \$0 is $0 echo \$1 is $1 echo \$2 is $2 echo \$$ is $$ echo \$# is $# echo \$* is $* echo \$@ is $@
先执行
./cmdargs.sh脚本, 然后输出
$?脚本的退出状态,运行结果如下:
$ ./cmdargs.sh I love my daughter $0 is ./cmdargs.sh $1 is I $2 is love $$ is 197 $# is 4 $* is I love my daughter $@ is I love my daughter $ echo $? 0
$*
和 $@
的区别
对照这个源码和输出结果,这些特殊变量应该可以分清楚了,其中
$*和
$@都是把所有内容都列出来了,但它俩还是有点区别的,当这两个变量都被双引号包裹时,通过
for循环会得到不同结果,写个脚本
cmdargs2.sh试一下
#!/bin/bash echo "test for \"\$*\"" for var in "$*" do echo "$var" done echo "test for \"\$@\"" for var in "$@" do echo "$var" done
运行结果如下,
"$*"把所有的参数当成了一个整体,而
"$@"把各个参数都拆分开了,可以通过循环依次打印出来。
$ ./cmdargs2.sh I love my daughter test for "$*" I love my daughter test for "$@" I love my daughter
条件判断
说起条件判断第一反应就是
if了,在
Shell脚本中也有
if语句,同样是条件判断的中坚力量,先来看看
if语句的写法:
if
语句格式
if [ -d $filename ]; then echo "this is a directory." elif [ -a $filename ]; then echo "the file is exist." else echo "the file is not exist." fi
直接提供一个最复杂的情况,如果不需要
elif或者
else分支,直接删掉就可以,但是
if、
then、
fi这些都是必须的,并且中括号里面的表达式与中括号之间都要有空格,如果挨着写会报错的。
中括号 []
的作用
一度认为
if条件语句就是这样写,中括号
[]应该是语法的一部分,但是查询后发现这居然是一个命令,和
ls,
pwd一样是一个可以执行命令,放在
if条件判断时基本等同于
test命令。
$ which [ /usr/bin/[ $ which test /usr/bin/test
看着这个查询结果感觉神奇吧,此外还有一个
[[]]双中括号的操作,这个就不是命令了,而是
Shell的一个关键字,比
[]要强大的多。
具体条件
Shell脚本最常见的条件就是文件判断,数字判断和字符串判断了,接下来列举一下这些判断的常见写法。
文件判断
命令 | 含义 |
---|---|
-a $filename | 文件存在时为真 |
-d $filename | 文件名对应的是目录时为真 |
-s $filename | 文件非空时为真 |
-r $filename | 文件可读时为真 |
-w $filename | 文件可写时为真 |
-x $filename | 文件可执行时为真 |
数字判断
命令 | 含义 |
---|---|
n1 -eq n2 | n1等于n2时为真 |
n1 -ne n2 | n1不等n2时为真 |
n1 -gt n2 | n1大于n2时为真 |
n1 -lt n2 | n1小于n2时为真 |
n1 -ge n2 | n1大于等于n2时为真 |
n1 -le n2 | n1小于等于n2时为真 |
字符串判断
命令 | 含义 |
---|---|
-n str1 | str1字符串不为空串时值为真 |
-z str1 | str1字符串为空串时值为真 |
str1 == str2 | str1与str2相等时为真 |
str1 != str2 | str1与str2不等时为真 |
str1 > str2 | 按字典序str1排在str2后面时为真 |
str1 < str2 | 按字典序str1排在str2前面时为真 |
数字判断特殊写法
命令 | 含义 |
---|---|
(("$n1" == "$n2")) |
n1等于n2时为真 |
(("$n1" != "$n2")) |
n1不等n2时为真 |
(("$n1" > "$n2")) |
n1大于n2时为真 |
(("$n1" < "$n2")) |
n1小于n2时为真 |
(("$n1" >= "$n2")) |
n1大于等于n2时为真 |
(("$n1" <= "$n2")) |
n1小于等于n2时为真 |
逻辑关系运算符
命令 | 含义 |
---|---|
-a | 与操作,用于[]和 test操作符 |
-o | 或操作,用于[]和 test操作符 |
! | 取反操作,用于[]、 test操作符 和 [[]]关键字 |
&& | 与操作,用于[[]]关键字 |
|| | 或操作,用于[[]]关键字 |
这些逻辑写法千奇百怪的,写两个例子就慢慢就慢慢理解了,比如判断一个字符串不为空,并且这个字符串指定的目录还存在就可以写成
if [ -n "$1" -a -d "$1" ]; then echo $1 directory is exist fi
使用双小括号来比较数值变量,写在双小括号中的变量前面可以不加
$符号,还有诸多特权等着你去发现
num1=$1 num2=$2 if (( num1 > num2)); then echo num1 \> num2 fi
总之在学习这些条件比较的时候踩了不少坑,有很多情况都没有注意到,不过慢慢也适应了这种语法,但还是免不了会出现一个小问题,这里提供一个
Shell语法检查的在线网站 《shellcheck》,将要检查的脚本放到页面上检测,会给出详细的错误信息,当然也有命令版本,可以自己到对应的 github 页面上下载哦~
总结
Shell
脚本中获取命令的执行结果,可以通过反引号`
command`
,或者小括号$(command)
的方式得到Shell
脚本中有一系列$
开头的变量,用好他们是脚本和函数传递参数的关键Shell
脚本中的条件判断对于初学者来说很头大,有许多注意的点要记住,判断形式也多种多样- 脚本中有单引号、双引号、反引号,简单来记就是单引号中原样输出,双引号中变量求值后输出,反引号中只能写需要执行的命令
- 脚本中还要中括号、双中括号、小括号、双小括号等,上面都提到过,可以自己练习下,具体的细节怕是要单独总结了,放到一起太多了
- 脚本的中的分号起到语句结束的作用,如果有换行就不需要分号了,比如
if
条件后面的then
如果换行,那么then
前面的分号可以省略 - 再记住一个坑,脚本赋值等号两端不能有空格,脚本判断等号两端必须有空格
有些局,选择不入便立于不败之地,选择介入,即使曾身经百战,也恐难全身而退,更不要谈什么收益了~
相关文章推荐
- shell脚本结构、date命令、变量 shell脚本中的逻辑判断 文件目录属性判断 if特殊用法 case判断
- shell脚本编程之条件判断,算术运算,整数测试及特殊变量
- shell脚本中蛮量替换(将命令运行结果存入变量中)
- centos shell编程5 LANMP一键安装脚本 lamp sed lnmp 变量和字符串比较不能用-eq cat > /usr/local/apache2/htdocs/index.php <<EOF重定向 shell的变量和函数命名不能有横杠 平台可以用arch命令,获取是i686还是x86_64 curl 下载 第三十九节课
- Mysql 将结果保存到文件 从文件里运行sql语句 记录操作过程(tee 命令的使用)
- Linux(7) 常用命令扩展 改变用户环境变量 (可以实现登陆就执行shell脚本)
- Winform下动态执行JavaScript脚本获取运行结果,谈谈网站的自动登录及资料获取操作
- makefile中使用shell命令并将结果保存为变量
- 脚本中判断Shell命令执行结果
- 使用expect实现自动交互,shell命令行自动输入,脚本自动化,变量引用,expect spawn执行带引号命令,expect 变量为空,不生效,不能匹配通配符*,函数,数组
- 小白使用Linux可执行文件须知操作(包括:文件上传,命令全称,命令含义,文件解压,路径设置,sh脚本运行)
- Shell脚本学习(一):shell变量和一些常用命令
- mysql常用操作命令, mysql脚本优化工具使用说明
- shell脚本的使用---if条件判断
- shell脚本的使用---特殊变量及脚本的综合使用
- php 执行linux命令,shell脚本函数,获取服务器运行状态值
- shell 脚本中获取变量时控制开始字符位置--使用冒号加数字
- Winform下动态执行JavaScript脚本获取运行结果,谈谈网站的自动登录及资料获取操作
- shell中常用系统变量和条件判断
- shell脚本之变量、变量类型、条件测试、算术运算、及特殊变量