bash3---基本2

1、和let一样,[[   ]]也是一个bash命令,但是sh没有的。 下次对于sh: XXX:not found 可以通过把sh换成bash试试

2、关于NULL的if。od探究

对于NULL=040时候,NULL is false for if

对于a=040,即变量是NULL时候 if [ -n "$a" ] 也是false.(对于字符串 -n表示字符串长度>0return true,而NULL代表字符串长度=0)

但是对于if [ -n $a] 相当于if [ -n ] 缺少了string,这两个的返回值都是true ,虽然我觉得这种语法是错误的。

总结if:

if [ ... ]

...所在的测试条件:

1、对于任何单独的数字返回都是true

2、对于任何的字符串返回都是true

3、对于直接输入的NULL(即space ,tab),返回为false

4、对于变量=NULL if[ 变量 ],返回为false

5、对于变量=NULL,if[ "变量"],返回为false

5、对于if [ -n "$变量名(=NULL)" ],返回是false

6、对于if [ - n ]返回是true,或者说if [ -n "string" ]中的string必须加"",这是一个非常好的习惯!当然if [ "string" ]也可以判断string 是否为空,

  就像Stephane Chazelas所指出的,
     # if [ $string1 ] 只有一个参数, "]"
    # if [ "$string1" ] 有两个参数, 一个是空的"$string1", 另一个是"]"

    #一个足智多谋的例子:string1="a = b"对于if [ $string1 ]将会显示出错!

 

7、对于if[ $false ]和if[ "$false" ] 返回是false, 对于if [ false ]相当于2是true

 

如果if和then在条件判断的同一行上的话, 必须使用分号来结束if表达式. if和then都关键字. 关键字(或者命令)如果作为表达式的开头, 并且如果想在同一行上再写一个新的表达式的话, 那么必须使用分号来结束上一句表达式 。

 

3、(( 1 / 0 )) 2>/dev/null

文件描述符我们常见的就是系统预留的0,1和2这三个,他们的意义分别有如下对应关系:

    • 0 —— stdin(标准输入)
    • 1 —— stdout (标准输出)
    • 2 —— stderr (标准错误)

/dev/null是一个特殊的设备文件,这个文件接收到的任何数据都会被丢弃。因此,null这个设备通常也被成为位桶(bit bucket)或黑洞。

深入关于重定向:

在Xsession中有这么一段:
  xmessage > /dev/null 2>&1

首先回顾一下重定向:

  1、command 1>filename相当于(command)1>filename相当于command >filename

  2、command 1>/dev/null 2>&1  ,这里&相当于等效于标准输出。重定向command的stderr到stdout中。 

  3、command &>filename 重定向command的stdout和stderr到filename中.

  4command >&2 重定向command的stdout到stderr中.  

  5、scriptname >>filename 把scriptname的输出追加到文件filename中. 如果filename不存在的话,将会被创建.

  6、[i]<>filename 打开文件filename用来读写, 并且分配文件描述符i给这个文件. 如果filename不存在, 这个文件将会被创建。

举个例子:

  //test.sh
  #!/bin/sh
  t
  date
 

这里的"t"是没有这个命令的,所以会输出stderr。

执行./test.sh > res1.log结果为

我们发现stderr并没有被重定向到res1.log中,stderr被打印到了屏幕上。这也进一步证明了上面说的./test.sh > res1.log等价于./test.sh 1>res1.log

执行./test.sh>res2.log 2>&1结果为两句都输出到res2.log。

这里的2 >&1是吧stderr重定向到stdout然后两句一次重定向到res2.log。

 

 

command >filename 2>filename 与command >a 2>&1的区别:

    还是上面的例子稍微改动一下:

  //test.sh
  #!/bin/sh
  t
  date 

  这里的"t"是没有这个命令的,所以会输出stderr。

  执行./test.sh >res1.log 2>&1

   结果res1.log中输入为./test.sh:line 2 : t:command not found

             The Jul 5 22:39:38 CST 2018

  执行./test.sh >res1.log 2>res1.log

   结果res1.log中输入为The Jul 5 22:39:38 CST 2018

             d not found

为什么呢?

  两者的区别在于区别就在于前者只打开一次文件a,后者会打开文件两次,并导致stderr被stdout覆盖。&1的含义就可以理解为用标准输出的引用,引用的就是重定向标准输出产生打开的a。从IO效率上来讲,command 1>a 2>&1比command 1>a 2>a的效率更高。

注意:1、这里是stderr被stdout覆盖,很显然,这个打印中 sdterr并没有被全部覆盖,而且stdout出现在了stderr上面。这里的命令应该是从右向左读的。

   2、如果把这个命令行参数改成./test.sh >>res1.log 2>res1.log,那么这个的结果和./test.sh >>res1.log 2>&1是一样的,但是实际情况还是有两次打开文件的区别。其中>>是追加输入的意思。

 

  

 

4、操作符

4.1、下面条件成立返回为真:

-e  exist

-f  一般文件

-s  size不为0

-d  direction

-b  block

-c  charecter

-p  pipe

-h  符号链接  

-L  符号链接

-s  socket

-t  文件描述符被关联到一个终端设备上

-r  read

-w  write

-x  exec

-nt    f1 new

-ot f1 old

-ef f1和f2是相同文件的硬链接

 4.2、其他比较操作符

整数比较:

-eq  等于  if [ "$a" -eq "$b" ]

-另外还有:ne  不等于

     -gt   大于

     -ge  大于等于

     -lt    小于

     -le   小于等于

<  小于(在双括号里使用)--->  (( "$a"< "$b" ))

另外还有:<= ,> ,>=

字符串比较

= 和==等价 if ["$a"=="$b" ]

!=不等号,  if [ "$a"!="$b" ],这个操作符在[[ ... ]]结构中使用表示模式匹配

<  小于,按照ASCII字符进行排序

>  大于,在if [ "$a" \> "$b" ]  >在[]中需要转义

-z  字符串为"null",字符串长度为0

-n  字符串不为"null"

 

 

4.3、模式匹配

[[ $a==z* ]]  #如果$a以"z"开头(模式匹配)那么结果为真

[[ $a=="z*" ]]  #如果$a与z*相等,那么结果为真

4.4、逻辑与或

-a 逻辑与  exp1 -a exp2。两个都为真,那么结果为真

-o 逻辑或  exp1 -o exp2。一个为真就是真。

这与bash中的&& ||比较像,但是&& ||用于[[ ... ]]中双括号结构中

if [ "$exp1" -a "$exp2" ]

注:

1、在一个混合测试时,即使使用引用的变量字符串也可能还不够,如果$string为空的话,[ -n "$string" -o "$a"="$b" ]可能出错。安全的做法是附加一个额外的字符给可能的空变量,[ "x$string" != x -o "x$a"="x$b" ](“ x”字符是可以相互抵消的)

最后抄一个例子:

 #!/bin/bash
 # zmore

 #使用'more'来查看gzip文件
 NOARGS=65
 NOTFOUND=66
 NOTGZIP=67
 if [ $# -eq 0 ] # 与if [ -z "$1" ]效果相同
 # (译者注: 上边这句注释有问题), $1是可以存在的, 可以为空, 如: zmore "" arg2 arg3
 then
 echo "Usage: `basename $0` filename" >&2
 # 错误消息输出到stderr.
 exit $NOARGS
 # 返回65作为脚本的退出状态的值(错误码).
 fi
 filename=$1
 if [ ! -f "$filename" ] # 将$filename引用起来, 这样允许其中包含空白字符.
 then
 echo "File $filename not found!" >&2
 # 错误消息输出到stderr.
 exit $NOTFOUND
 fi
 if [ ${filename##*.} != "gz" ]
 # 在变量替换中使用中括号结构.
 then
 echo "File $1 is not a gzipped file!"
 exit $NOTGZIP
 fi
 zcat $1 | more

 # 使用过滤命令'more.'
 # 当然, 如果你愿意, 也可以使用'less'.


 exit $? # 脚本将把管道的退出状态作为返回值.
 # 事实上, 也不一定非要加上"exit $?", 因为在任何情况下,
 # 脚本都会将最后一条命令的退出状态作为返回值.例子

 这个例子的逻辑很简单,就是先判断命令行参数有没有,第一个是不是.gz文件,都是的话,打开即可。

其中有这么几个点需要学习一下:

1、设置清楚错误码,

2、$#是命令行参数个数

3、&2是stderr

4、[ ! -f “$filename” ] 不是一个一般文件,就是不存在这个文件.

5、${$string##*.}  这个是重点,是字符串操作(包括提取,删除,替换):

6、如何测试?我的方法是: find /usr -name "*.gz" -type f -exec bash 7-7.sh '{}' ';'  #但是这种方法,可能会按q无法结束,因为有很多的.gz文件等着你去q,哈哈~按ctrl+C吧~

 

 

 

posted @ 2018-07-06 10:50  SsoZh  阅读(184)  评论(0编辑  收藏  举报