当前位置: 首页 > news >正文

Shell脚本中获取命令运行结果、特殊变量使用、条件判断等常用操作

文章目录

  • 前言
  • 获取命令执行结果
    • 使用反引号 `` ` ``command `` ` ``来执行命令
    • 使用括号组合 $(command) 来执行命令
    • 两种方式的区别
  • 特殊变量使用
    • $0 $1 $2 ...
    • $$
    • $?
    • $#
    • $*
    • $@
    • 测试
    • `$*` 和 `$@` 的区别
  • 条件判断
    • `if` 语句格式
    • 中括号 `[]` 的作用
    • 具体条件
      • 文件判断
      • 数字判断
      • 字符串判断
      • 数字判断特殊写法
      • 逻辑关系运算符
  • 总结

前言

最近在处理一个 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 分支,直接删掉就可以,但是 ifthenfi 这些都是必须的,并且中括号里面的表达式与中括号之间都要有空格,如果挨着写会报错的。

中括号 [] 的作用

一度认为 if 条件语句就是这样写,中括号 [] 应该是语法的一部分,但是查询后发现这居然是一个命令,和 lspwd 一样是一个可以执行命令,放在 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 n2n1等于n2时为真
n1 -ne n2n1不等n2时为真
n1 -gt n2n1大于n2时为真
n1 -lt n2n1小于n2时为真
n1 -ge n2n1大于等于n2时为真
n1 -le n2n1小于等于n2时为真

字符串判断

命令含义
-n str1str1字符串不为空串时值为真
-z str1str1字符串为空串时值为真
str1 == str2str1与str2相等时为真
str1 != str2str1与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 前面的分号可以省略
  • 再记住一个坑,脚本赋值等号两端不能有空格,脚本判断等号两端必须有空格

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

有些局,选择不入便立于不败之地,选择介入,即使曾身经百战,也恐难全身而退,更不要谈什么收益了~

相关文章:

  • gdb调试解决找不到源代码的问题
  • GDB调试指北大全
  • 小白眼中的docker究竟是个什么东西
  • GDB调试指北-启动GDB并查看说明信息
  • Redis源码-BFS方式浏览main函数
  • GDB调试指北-启动调试或者附加到进程
  • Python中时间戳、时间字符串、时间结构对象之间的相互转化
  • git log根据特定条件查询日志并统计修改的代码行数
  • C++中优先队列priority_queue的基础用法
  • C++求解组合数的具体实现
  • 东拉西扯01世界的沧海桑田
  • Go语言在解决实际问题时的优点与不便
  • 使用Spreadsheet Compare工具对比Excel文件差异
  • linux环境下使用sort命令完成常见排序操作
  • 关于数据一致性的思考
  • Google 是如何开发 Web 框架的
  • es6(二):字符串的扩展
  • ES6语法详解(一)
  • Java的Interrupt与线程中断
  • Map集合、散列表、红黑树介绍
  • Nacos系列:Nacos的Java SDK使用
  • nodejs实现webservice问题总结
  • TypeScript迭代器
  • webpack4 一点通
  • 免费小说阅读小程序
  • 异常机制详解
  • MyCAT水平分库
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • #每日一题合集#牛客JZ23-JZ33
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • $.ajax,axios,fetch三种ajax请求的区别
  • %3cli%3e连接html页面,html+canvas实现屏幕截取
  • (02)vite环境变量配置
  • (11)MSP430F5529 定时器B
  • (14)学习笔记:动手深度学习(Pytorch神经网络基础)
  • (4) openssl rsa/pkey(查看私钥、从私钥中提取公钥、查看公钥)
  • (C语言)fread与fwrite详解
  • (MATLAB)第五章-矩阵运算
  • (Repost) Getting Genode with TrustZone on the i.MX
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (二)丶RabbitMQ的六大核心
  • (附表设计)不是我吹!超级全面的权限系统设计方案面世了
  • (附源码)springboot家庭装修管理系统 毕业设计 613205
  • (附源码)ssm基于jsp的在线点餐系统 毕业设计 111016
  • (三)elasticsearch 源码之启动流程分析
  • (十七)devops持续集成开发——使用jenkins流水线pipeline方式发布一个微服务项目
  • (十三)Java springcloud B2B2C o2o多用户商城 springcloud架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)...
  • (数据结构)顺序表的定义
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (转)清华学霸演讲稿:永远不要说你已经尽力了
  • .net core控制台应用程序初识
  • .Net 知识杂记
  • .NET版Word处理控件Aspose.words功能演示:在ASP.NET MVC中创建MS Word编辑器
  • .NET企业级应用架构设计系列之技术选型