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>89
echo 'A'
elif test $i -gt 79; then #如果i>79
echo '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>0
echo 'D'
elif test $i -lt 0;then #如果i<0
echo '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 ]; then
echo 'A'
elif [ $i -gt 79 ]; then
echo 'B'
elif [ $i -eq 60 -o $i -gt 60 ]; then
echo 'C'
elif [ $i -gt 0 ]; then
echo 'D'
elif [ $i -lt 0 ]; then
echo 'invalid'
else
echo '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" ]; then
echo 'str1 is empty'
else
echo 'str1 is not empty'
fi printf "\n" str2=""
if [ -n "$str2" ]; then
echo 'str2 is not empty'
else
echo 'str2 is empty'
fi printf "\n" if [ "$str1" = "$str2" ]; then
echo 'str1 = str2'
else
echo '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 ]; then
echo '~/.bash_profile is a file'
else
echo '~/.bash_profile is not a file'
fi printf '\n' if [ -d ~/ ]; then
echo '~/ is a directory'
else
echo '~/ 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/bash echo 'param count: ' $#
echo 'first param: ' $1
if [ $# -eq 1 ] && (echo $1 | grep ^[0-9]*$ >/dev/null); then
echo 'param check pass!'
else
echo '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!'
就不解释了,大家自己体会吧。
bash/shell编程学习(2)的更多相关文章
- bash/shell编程学习(3)
接上节继续, 1. 从键盘读取输入内容 #!/bin/bash read -p 'please input something:' input echo 'your input:' $input 运行 ...
- bash/shell编程学习(1)
1)定义变量 myvar=abc #注:等号前后不能加空格 #或 myvar="abc" #或 myvar='abc' #注:如果变量后面的值中间本身没有空格,加不加引号都无所谓, ...
- Bash脚本编程学习笔记08:函数
官方资料:Shell Functions (Bash Reference Manual) 简介 正如我们在<Bash脚本编程学习笔记06:条件结构体>中最后所说的,我们应该把一些可能反复执 ...
- Bash脚本编程学习笔记07:循环结构体
本篇中涉及到算术运算,使用了$[]这种我未在官方手册中见到的用法,但是确实可用的,在此前的博文<Bash脚本编程学习笔记03:算术运算>中我有说明不要使用,不过自己忘记了.大家还是尽量使用 ...
- abc高级bash shell编程
http://www.pythoner.com/122.html abc高级bash shell编程
- Linux 下shell 编程学习脚手架
linux body { font-family: Helvetica, arial, sans-serif; font-size: 14px; line-height: 1.6; padding-t ...
- linux 10 -Bash Shell编程
二十三. Bash Shell编程: 1. 读取用户变量: read命令是用于从终端或者文件中读取输入的内建命令,read命令读取整行输入,每行末尾的换行符不被读入.在read命令后 ...
- Bash脚本编程学习笔记06:条件结构体
简介 在bash脚本编程中,条件结构体使用if语句和case语句两种句式. if语句 单分支if语句 if TEST; then CMD fi TEST:条件判断,多数情况下可使用test命令来实现, ...
- shell编程学习之使用jq对json数据进行提取
shell编程学习之使用jq对json提取 jq命令允许直接在命令行下对JSON进行操作,包括分片.过滤.转换等 ,jq是用C编写,没有运行时依赖,所以几乎可以运行在任何系统上.预编译的二进制文件可以 ...
随机推荐
- 高性能 TCP & UDP 通信框架 HP-Socket v3.2.3
HP-Socket 是一套通用的高性能 TCP/UDP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#.Del ...
- UEditor编辑器的使用
1.首先我们要去官网下载UEditor编辑器,选择语言,这里我用的是php utf-8版本(李昌辉) 2.下载完成之后解压文件,将解压的文件放到我们的网站目录里面 3.ueditor/utf8-php ...
- 带你使用h5开发移动端小游戏
带你使用h5开发移动端小游戏 在JY1.x版本中,你要做一个pc端的小游戏,会非常的简单,包括说,你要在低版本的浏览器IE8中,也不会出现明显的卡顿现象,你只需要关心游戏的逻辑就行了,比较适合逻辑较为 ...
- sharepoint报HRESULT:0x80131904的错误的原因和解决方法
在新建文件库的时候出现的.下上传文件和更改权限,都是在报这个HRESULT:0x80131904的错误,基本所有操作都报同一个错误,如下图: 错误原因 这个问题其实就是:sharepoint配置文件( ...
- SharePoint 2013 入门教程之创建及修改母版页
在SharePoint 2013中,微软提供了根据HTML页面转换Master页的方法,并支持单项同步,但是这样的更新,并不完善,会使一些功能造成丢失,所以,了解Master结构的人,尽量直接去修改M ...
- Android—ZXing二维码扫描遇到的问题
最近工作中需要开发带有二维码扫描功能的软件(基于开源项目ZXing),遇到的问题记录一下,也希望给大家带来帮助. 1.首先因为扫描要开摄像机所以加权限是一定的,不然后面什么都不能进行 <uses ...
- JSPatch使用小记
hotfix的作用众所周知,Android和iOS都有各自的技术,但是相比Android的当天发布来说(如果你们的项目不需要灰度),iOS热更新的意义更加重大.因为iOS审核周期长不说,而且运气不好会 ...
- Android Studio调试方法学习笔记
(注:本人所用Android Studio的Keymap已设为Eclipse copy) 1.设置断点 只有设置断点,才好定位要调试什么地方,否则找不到要调试的地方,无法调试.(调试过程中也可以增加断 ...
- Android 热修复技术(1)---原理
热修复技术分为几部分: 原理介绍 Android HotFix源码分析 自定义框架 1.Android分包MultiDex原理 首先Dex是什么东西? Dex就是Window里面的exe文件 也就是可 ...
- 0027 Java学习笔记-面向对象-(非静态、静态、局部、匿名)内部类
内部类 内部类就是把一个类写在另一个类的内部 用途: 如果一个类只希望它被某一个类访问,那么可以把它定义在另一个类的内部,并用private修饰 内部类可以访问它所在外部类的private成员:但所在 ...