• 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吧~

     

  • 相关阅读:
    iOS 9 ContactsFramework
    performSelector延时调用导致的内存泄露
    ARC 下内存泄露的那些点
    CoreText.framework --- 基本用法
    edgesForExtendedLayout
    CocoaPods使用详细说明
    IOS开发笔记(11)IOS开发之NSLog使用技巧
    网页中调用JS与JS注入
    Block就像delegate的简化版
    转:UINavigationBar--修改导航栏返回按钮的文字
  • 原文地址:https://www.cnblogs.com/SsoZhNO-1/p/9249130.html
Copyright © 2020-2023  润新知