bash/shell编程学习(2)

先来复习上节重定向的用法:

1.快速清空文件

cat demo.txt < /dev/null

注:linux中有一个经典名言【一切皆文件】,/dev/null可以认为是一个特殊的空文件,更形象点,可以理解为科幻片中的黑洞,任何信息重向定输出到它后,便有去无回,当然黑洞里也没有信息能出来。

综合来讲,上面的意思就是利用<将黑洞做为demo.txt的标准输入,黑洞里没任何内容,任何文件里的内容被它吞噬了,自然也没就没东西能剩下了,所以最终就是demo.txt被黑洞洗空了。

/dev/null 还有其它用法,比如用它可以让nohup不生成nohup.out文件,见:http://www.cnblogs.com/yjmyzz/p/4831182.html 

 

2.执行时输出源码

#!/bin/bash -v
printf '%0.2f\n' 12.12334

执行结果如下:

#!/bin/bash -v
printf '%0.2f\n' 12.12334
12.12

注意:第3行输出结果之前,把源码也打印出来了,秘密在于第1行最后的 -v 参数 

 

3.调试模式

#!/bin/bash -x
printf '%0.2f\n' 12.12334
echo 'hello'

执行结果如下:

+ printf '%0.2f\n' 12.12334
12.12
+ echo hello
hello

注意:第一行后面的参数变成了-x,加上这个后,执行时,每一行代码在执行前,会先输出对应的源码,并且以+开头,十分方便调试。  

 

4. if与test及[]

4.1 数字判断

#!/bin/bash -x
i=$1 #变量i的值取第1个参数的值
if test $i -gt 89; then #如果i>89echo 'A'
elif test $i -gt 79; then #如果i>79echo 'B'
elif test $i -eq 60 -o $i -gt 60;then #如果i=60或i>60(即:i>=60)echo 'C'
elif test $i -gt 0;then #如果i>0echo 'D'
elif test $i -lt 0;then #如果i<0echo 'invalid'
else #i==0的情况echo 'zero' 
fi

注:if test 条件; then 语句 fi 这是基本格式,注意条件后的;不可省略,另外结束符号是fi(即:把if倒过来,有点回文的理念),另外要记住一堆缩写

-lt 即-Less Than的缩写,表示小于

-gt 即-Greater Than的缩写,表示大于

-eq 即-equal的缩写,表示等于,此外还有

-ne 即-Not Equal的缩写,表示不等于

-o 即-or,表示前后二个逻辑判断是『』的关系,类似的

-a 即-and,表示前后二个逻辑判断是『』的关系

elif 即else if的缩写 

上面的示例运行结果:

./demo.sh 90
+ i=90
+ test 90 -gt 89
+ echo A
A

test语句还有一个简化的写法,即把"test 条件"变成" [ 条件 ] ",注意二端的方括号左右都要加一个空格,所以上面的写法可以改成:

i=$1
if [ $i -gt 89 ]; thenecho 'A'
elif [ $i -gt 79 ]; thenecho 'B'
elif [ $i -eq 60 -o $i -gt 60 ]; thenecho 'C'
elif [ $i -gt 0 ]; thenecho 'D'
elif [ $i -lt 0 ]; thenecho 'invalid'
elseecho 'zero'
fi

这样看起来就美观多了,如果不喜欢-o这种逻辑或的写法,第6行也可以换成这样

elif [ $i -eq 60 ] || [ $i -gt 60 ]; then

但是执行的细节略有区别,在调试模式下可以对比下,用||写法的输入(测试用例:61)

./demo2.sh 61
+ i=61
+ '[' 61 -gt 89 ']'
+ '[' 61 -gt 79 ']'
+ '[' 61 -eq 60 ']'
+ '[' 61 -gt 60 ']'
+ echo C
C

而用-o写法的输出:

./demo2.sh 61
+ i=61
+ '[' 61 -gt 89 ']'
+ '[' 61 -gt 79 ']'
+ '[' 61 -eq 60 -o 61 -gt 60 ']'
+ echo C
C

对比下5-6行可以发现,区别在于判断一次,还是判断二次 

4.2 字符串判断

#!/bin/bash -x
str1="abc"
if [ -z "$str1" ]; thenecho 'str1 is empty'
elseecho 'str1 is not empty'
fiprintf "\n"str2=""
if [ -n "$str2" ]; thenecho 'str2 is not empty'
elseecho 'str2 is empty'
fiprintf "\n"if [ "$str1" = "$str2" ]; thenecho 'str1 = str2'
elseecho 'str1 <> str2'
fi

注: -n即-not empty判断字符串非空,-z即-zero判断字符串为空,=判断字符串相同(判断字符串时,记得要加双引号)

运行结果:

+ str1=abc
+ '[' -z abc ']'
+ echo 'str1 is not empty'
str1 is not empty
+ printf '\n'+ str2=
+ '[' -n '' ']'
+ echo 'str2 is empty'
str2 is empty
+ printf '\n'+ '[' abc = '' ']'
+ echo 'str1 <> str2'
str1 <> str2

4.3 文件及目录判断

#!/bin/bash -x
if [ -f ~/.bash_profile ]; thenecho '~/.bash_profile is a file'
elseecho '~/.bash_profile is not a file'
fiprintf '\n'if [ -d ~/ ]; thenecho '~/ is a directory'
elseecho '~/ is not a directory'
fi

-f即判断是否为file, -d即判断是否为directory, 输出结果:

+ '[' -f /Users/yjmyzz/.bash_profile ']'
+ echo '~/.bash_profile is a file'
~/.bash_profile is a file
+ printf '\n'+ '[' -d /Users/yjmyzz/ ']'
+ echo '~/ is a directory'
~/ is a directory

 

5.命令列表

命令1 && 命令2

解释:如果命令1返回成功,则命令2会执行,示例:

#!/bin/bash
ping -c 4 $1 && printf '\n==== %s connected ====\n' $1

将上面这段保存成testurl.sh,然后chmod +x testurl.sh,执行效果如下:

./testurl.sh www.baidu.com
PING www.a.shifen.com (115.239.211.112): 56 data bytes
64 bytes from 115.239.211.112: icmp_seq=0 ttl=50 time=9.950 ms
64 bytes from 115.239.211.112: icmp_seq=1 ttl=50 time=23.994 ms
64 bytes from 115.239.211.112: icmp_seq=2 ttl=50 time=12.272 ms
64 bytes from 115.239.211.112: icmp_seq=3 ttl=50 time=19.717 ms--- www.a.shifen.com ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 9.950/16.483/23.994/5.641 ms==== www.baidu.com connected ====

如果把后面的参数 ,换成某个不能访问的网址,比如在伟大的墙内,可以试下:

./testurl.sh www.google.com
PING www.google.com (216.58.197.100): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2--- www.google.com ping statistics ---
4 packets transmitted, 0 packets received, 100.0% packet loss

命令1 || 命令2

解释:这个正好跟&&相反,如果命令1返回失败,则执行命令2

#!/bin/bash
ping -c 4 $1 || printf '\n==== %s connect fail ====\n' $1

把这个保存成testurl2.sh ,然后重复刚才的测试

./testurl2.sh www.google.com
PING www.google.com (216.58.199.4): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2--- www.google.com ping statistics ---
4 packets transmitted, 0 packets received, 100.0% packet loss==== www.google.com connect fail ====

通过刚才的测试,相信大家已经掌握&&与||的用法了,那么问题来了,如何判断前一个命令的执行结果是【成功】还是【失败】呢

先回忆一下,大学里《C程序设计》里老师讲的内容,C程序里main函数,如果运行成功,最后一般会约定返回return 0,没错bash里就是这么判断的

(再提一个问题:为什么要跟C扯上关系?因为linux里的很多bash命令,就是拿C/C++来开发的),我们可以来验证下:

#include <stdio.h>
#include <stdlib.h>
int main(int argc,char **argv){printf("hello world and this function will return 0\n");return 0;
}

这是一段c语言的代码,保存成hello1.c,然后输入gcc -o hello1 hello1.c (mac本上只要安装了xcode,就已经自带了gcc编译器),然后会在当前目录下生成hello1的可执行文件,做为对比,再来一个hello2.c

#include <stdio.h>
#include <stdlib.h>
int main(int argc,char **argv){printf("hello world and this function will return 1\n");return 1;
}

同样编译成hello2,然后测试:

./hello1 && echo 'hello1 is ok'
hello world and this function will return 0
hello1 is ok

再来一个

./hello2 && echo 'you can not see this'
hello world and this function will return 1

小结:这跟很多语言里约定1代表true, 0代表false正好是反的,在bash里,如果一个命令执行后返回0,表示成功,返回1表示失败。  

 

6. 检测参数个数及类型

最后结合前面学到的知识,做一个小小的综合练习:

#!/bin/bashecho 'param count: ' $#
echo 'first param: ' $1
if [ $# -eq 1 ] && (echo $1 | grep ^[0-9]*$ >/dev/null); thenecho 'param check pass!'
elseecho 'only one integer parameter is accepted!'
fi

上面这段代码的意思是仅接收1个整型的参数,将这段代码保存成check1.sh,然后试着运行下:

./check1.sh a b 2
param count:  3
first param:  a
only one integer parameter is accepted!

再试下:

./check1.sh 123
param count:  1
first param:  123
param check pass!

第5行的那个长长的if判断,初次看估计比较晕,我们来分解一下:

第一部分

[ $# -eq 1]

其中$#表示参数的个数,-eq 1 要求参数个数必须等于1

第二部分

(echo $1 | grep ^[0-9]*$ >/dev/null) 

仍然有点复杂,再细分一下,先不管最后的>/dev/null,将其去掉,然后简化一下:

grep 用于字符查找及过滤,见下面的图:

  

who用于显示本机有哪些用户登录了,以及登录的终端信息,加上管道符|,将输出结果传递给grep 001 ,最后就从who的一堆结果中,过滤出包含001的信息了。

再回过头,看下这个:

echo 123 | grep ^[0-9]*$

会输出123(注:如果mac上将终端改成了zsh,直接运行会报错zsh: no matches found: ^[0-9]*$,解决办法:新建一个.sh脚本文件,写在脚本文件里就能运行了),grep后的部分是一个正则表达式,匹配0-9中的1个或多个,最后再来看:

(echo $1 | grep ^[0-9]*$ >/dev/null)

现在应该能看懂了吧,将1个参数输出,然后做为grep的输入,正常情况下,如果第1个参数为数字,则会输出,但是我们的本意是放在if条件判断中,并不希望将其输出,所以最后重定向到黑洞。

结合前面的命令列表&&,可以将这段if简化成终极版本:

#!/bin/bash -x! ([ $# -eq 1 ] && (echo $1 | grep ^[0-9]*$ >/dev/null)) && echo 'only one integer parameter is accecpted ' &&  exit 1
echo 'param check pass!'

就不解释了,大家自己体会吧。  

  

转载于:https://www.cnblogs.com/yjmyzz/p/bash-shell-programming-study-2.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/471171.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 2187. 完成旅途的最少时间(二分查找)

文章目录1. 题目2. 解题1. 题目 给你一个数组 time &#xff0c;其中 time[i] 表示第 i 辆公交车完成 一趟旅途 所需要花费的时间。 每辆公交车可以 连续 完成多趟旅途&#xff0c;也就是说&#xff0c;一辆公交车当前旅途完成后&#xff0c;可以 立马开始 下一趟旅途。 每辆…

Web框架——Flask系列之综合案例——图书管理系统(十)

一、知识点: 表单创建数据库操作一对多关系演练 二、实现步骤: 创建数据库配置信息,定义模型类创建数据库表,添加测试数据编写html页面,展示数据添加数据删除书籍,删除作者 三、创建数据库连接信息,定义模型 from flask import Flask, render_template, redirect, url_for,…

LeetCode 2190. 数组中紧跟 key 之后出现最频繁的数字

文章目录1. 题目2. 解题1. 题目 给你一个下标从 0 开始的整数数组 nums &#xff0c;同时给你一个整数 key &#xff0c;它在 nums 出现过。 统计 在 nums 数组中紧跟着 key 后面出现的不同整数 target 的出现次数。换言之&#xff0c;target 的出现次数为满足以下条件的 i 的…

Web框架——Flask系列之request请求参数详解(十一)

一、request参数 request 就是flask中代表当前请求的 request 对象&#xff0c;其中一个请求上下文变量(理解成全局变量&#xff0c;在视图函数中直接使用可以取到当前本次请求) from flask import request 就是Flask中表示当前请求的request对象&#xff0c;request对象中保存…

LeetCode 2191. 将杂乱无章的数字排序(自定义排序)

文章目录1. 题目2. 解题1. 题目 给你一个下标从 0 开始的整数数组 mapping &#xff0c;它表示一个十进制数的映射规则&#xff0c;mapping[i] j 表示这个规则下将数位 i 映射为数位 j 。 一个整数 映射后的值 为将原数字每一个数位 i &#xff08;0 < i < 9&#xff…

LeetCode 2192. 有向无环图中一个节点的所有祖先(拓扑排序)

文章目录1. 题目2. 解题1. 题目 给你一个正整数 n &#xff0c;它表示一个 有向无环图 中节点的数目&#xff0c;节点编号为 0 到 n - 1 &#xff08;包括两者&#xff09;。 给你一个二维整数数组 edges &#xff0c;其中 edges[i] [fromi, toi] 表示图中一条从 fromi 到 t…

Web框架——Flask系列之Flask创建app对象 路由(十二)

一、初始化参数 import_name: 当前模块名 static_url_path:静态资源的url前缀&#xff0c;默认为‘static’ static_folder: 静态文件目录名&#xff0c;默认‘static’ template_folder: 模板文件目录名&#xff0c;默认‘templates’ 二、配置参数 app.config.from_pyfil…

bootstrap在iframe框架中实现由子页面在顶级页面打开模态框(modal)

我需要完成的效果&#xff1a; 1.在顶级页面打开模态框&#xff0c;并且遮罩层也要再顶级页面 2.单击遮罩层部分&#xff0c;模态框不关闭 问题描述&#xff1a; 不知为什么&#xff0c;可能是bootstrap前端框架添加遮罩层的一些问题。通过子页面在顶级页面打开模态框&#xff…

RIP协议及距离向量算法(详解)

一、路由选择协议分类回顾 二、RIP协议 RIP是一种分布式的基于距离向量的路由选择协议&#xff0c;是因特网的协议标准&#xff0c;最大优点是简单。 RIP协议要求网络中每一个路由器都维护从它自己到其他每一个目的网络的唯一最佳距离记录&#xff08;即一组距离&#xff09;。…

LeetCode 2194. Excel 表中某个范围内的单元格

文章目录1. 题目2. 解题1. 题目 Excel 表中的一个单元格 (r, c) 会以字符串 "<col><row>" 的形式进行表示&#xff0c;其中&#xff1a; <col> 即单元格的列号 c 。用英文字母表中的 字母 标识。 例如&#xff0c;第 1 列用 ‘A’ 表示&#xff…

OSPF协议及链路状态算法(详解)

一、路由选择协议分类回顾 二、OSPF协议 开放最短路径优先OSPF协议&#xff1a;“开放”标明OSPF协议不是受某一家厂商控制&#xff0c;而是公开发表的&#xff1b;“最短路径优先”是因为使用了Dijkstra提出的最短路径算法SPF。OSPF最主要的特征就是使用分布式的链路状态协议…

LeetCode 2196. 根据描述创建二叉树(哈希)

文章目录1. 题目2. 解题1. 题目 给你一个二维整数数组 descriptions &#xff0c;其中 descriptions[i] [parenti, childi, isLefti] 表示 parenti 是 childi 在 二叉树 中的 父节点&#xff0c;二叉树中各节点的值 互不相同 。此外&#xff1a; 如果 isLefti 1 &#xff0…

Web框架——Flask系列之abort函数与自定义异常处理(十三)

一、abort函数 使用abort函数可以立即终止视图函数的执行&#xff0c;并可以返回给前端特定的信息 传递状态码信息&#xff0c;必须是标准的http状态码 abort(403)传递响应体信息 resp Response(“login failed”) abort(resp) from flask import Flask,request,abort,Resp…

LeetCode 2197. 替换数组中的非互质数(栈)

文章目录1. 题目2. 解题1. 题目 给你一个整数数组 nums 。请你对数组执行下述操作&#xff1a; 从 nums 中找出 任意 两个 相邻 的 非互质 数。如果不存在这样的数&#xff0c;终止 这一过程。否则&#xff0c;删除这两个数&#xff0c;并 替换 为它们的 最小公倍数&#xff…

Web框架——Flask系列之json、jsonify模块的使用(十四)

一、字典与json之间的格式转换 json.dumps(字典) &#xff1a;将python的字典转换为json字符串json.loads(字符串) &#xff1a;将字符串转换为python中的字典 from flask import Flask import jsonapp Flask(__name__)app.route("/index",methods["GET&quo…

LeetCode 2195. 向数组中追加 K 个整数(贪心)

文章目录1. 题目2. 解题1. 题目 给你一个整数数组 nums 和一个整数 k 。 请你向 nums 中追加 k 个 未 出现在 nums 中的、互不相同 的 正 整数&#xff0c;并使结果数组的元素和 最小 。 返回追加到 nums 中的 k 个整数之和。 示例 1&#xff1a; 输入&#xff1a;nums [1,…

Web框架——Flask系列之设置和读取cookie(十五)

设置cookie,默认有效期是临时cookie&#xff0c;浏览器关闭就会失效 from flask import Flask,make_responseapp Flask(__name__)app.route("/set_cookie",methods["GET"]) def set_cookie():resp make_response("success")# 设置cookie&#…

LeetCode 2200. 找出数组中的所有 K 近邻下标

文章目录1. 题目2. 解题1. 题目 给你一个下标从 0 开始的整数数组 nums 和两个整数 key 和 k 。 K 近邻下标 是 nums 中的一个下标 i &#xff0c;并满足至少存在一个下标 j 使得 |i - j| < k 且 nums[j] key 。 以列表形式返回按 递增顺序 排序的所有 K 近邻下标。 示例…

Web框架——Flask系列之session机制(十六)

一、session机制图解 二、设置和获取session from flask import Flask,sessionapp Flask(__name__)# flask的session需要用到的密钥字符串 app.config["SECRET_KEY"] "Zepppppp"app.route("/login",methods["GET","POST"…

LeetCode 2201. 统计可以提取的工件(哈希)

文章目录1. 题目2. 解题1. 题目 存在一个 n x n 大小、下标从 0 开始的网格&#xff0c;网格中埋着一些工件。给你一个整数 n 和一个下标从 0 开始的二维整数数组 artifacts &#xff0c;artifacts 描述了矩形工件的位置&#xff0c;其中 artifacts[i] [r1i, c1i, r2i, c2i] …