设为首页 收藏本站
查看: 668|回复: 0

细读shell-3

[复制链接]

尚未签到

发表于 2018-8-24 10:25:06 | 显示全部楼层 |阅读模式
  14. $(( )) 与 $( ) 还有${ } 差在哪?
  在 bash shell 中,$( ) 与 ` ` (反引号) 都是用来做命令替换用(command substitution
  的。  所谓的命令替换与我们第五章学过的变量替换差不多,都是用来重组命令行:
  * 完成引号里的命令行,然后将其结果替换出来,再重组命令行。
  $ echo the last sunday is $(date -d "last sunday" +%Y-%m-%d)
  ` ` 很容易与 ' ' ( 单引号)搞混乱
  在多层次的复合替换中,` ` 须要额外的跳脱( \` )处理,而 $( ) 则比较直观
  command1 `command2 \`command3\` `
  ` ` 基本上可用在全部的 unix shell 中使用,若写成 shell script ,其移植性比较高。
  而 $( ) 并不见的每一种 shell 都能使用,我只能跟你说,若你用 bash2 的话,肯定没问题...
  再让我们看 ${ } 吧... 它其实就是用来作变量替换用的啦
  一般情况下,$var 与 ${var} 并没有啥不一样。
  但是用 ${ } 会比较精确的界定变量名称的范围,比方说:
  $ A=B
  $ echo $AB
  为了完整起见,我这里再用一些例子加以说明 ${ } 的一些特异功能:
  假设我们定义了一个变量为:
  file=/dir1/dir2/dir3/my.file.txt
  我们可以用 ${ } 分别替换获得不同的值:
  ${file#*/}:拿掉第一条 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt
  ${file##*/}:拿掉最后一条 / 及其左边的字符串:my.file.txt
  ${file#*.}:拿掉第一个 . 及其左边的字符串:file.txt
  ${file##*.}:拿掉最后一个 . 及其左边的字符串:txt
  ${file%/*}:拿掉最后条 / 及其右边的字符串:/dir1/dir2/dir3
  ${file%%/*}:拿掉第一条 / 及其右边的字符串:(空值)
  ${file%.*}:拿掉最后一个 . 及其右边的字符串:/dir1/dir2/dir3/my.file
  ${file%%.*}:拿掉第一个 . 及其右边的字符串:/dir1/dir2/dir3/my
  记忆的方法为:
  # 是去掉左边(在鉴盘上 # 在 $ 之左边)
  % 是去掉右边(在鉴盘上 % 在 $ 之右边)
  单一符号是最小匹配﹔两个符号是最大匹配。
  ${file:0:5}:提取最左边的 5 个字节:/dir1
  ${file:5:5}:提取第 5 个字节右边的连续 5 个字节:/dir2
  
  我们也可以对变量值里的字符串作替换:
  ${file/dir/path}:将第一个 dir 提换为 path:/path1/dir2/dir3/my.file.txt
  ${file//dir/path}:将全部 dir 提换为 path:/path1/path2/path3/my.file.txt
  
  利用 ${ } 还可针对不同的变量状态赋值(没设定、空值、非空值):
  ${file-my.file.txt} :假如 $file 没有设定,则使用 my.file.txt 作传回值。(空值及非空值
  时不作处理)
  ${file:-my.file.txt} :假如 $file 没有设定或为空值,则使用 my.file.txt 作传回值。 (非空
  值时不作处理)
  ${file+my.file.txt}  :不管  $file  为何值,均使用  my.file.txt  作传回值。
  ${file:+my.file.txt} :若 $file 为非空值,则使用 my.file.txt 作传回值。 (没设定及空值
  时不作处理)
  ${file=my.file.txt} :若 $file 没设定,则使用 my.file.txt 作传回值,同时将 $file 赋值
  为 my.file.txt 。 (空值及非空值时不作处理)
  ${file:=my.file.txt} :若 $file 没设定或为空值,则使用 my.file.txt 作传回值,同时将
  $file 赋值为 my.file.txt 。 (非空值时不作处理)
  ${file?my.file.txt} :若 $file 没设定,则将 my.file.txt 输出至 STDERR。 (空值及非空
  值时不作处理)
  ${file:?my.file.txt} :若 $file 没设定或为空值,则将 my.file.txt 输出至 STDERR。 (非
  空值时不作处理)
  还有哦,${#var} 可计算出变量值的长度:
  ${#file} 可得到 27 ,因为 /dir1/dir2/dir3/my.file.txt 刚好是 27 个字节...
  
  15.数组array
  接下来,再为大家介稍一下 bash 的组数(array)处理方法。
  一般而言,A="a b c def" 这样的变量只是将 $A 替换为一个单一的字符串,
  但是改为 A=(a b c def) ,则是将 $A 定义为组数...
  bash 的组数替换方法可参考如下方法:
  ${A[@]} 或 ${A
  • } 可得到 a b c def (全部组数)
      ${A[0]} 可得到 a (第一个组数),${A[1]} 则为第二个组数...
      ${#A[@]} 或 ${#A
  • } 可得到 4 (全部组数数量)
      ${#A[0]} 可得到 1 (即第一个组数(a)的长度),${#A[3]} 可得到 3 (第四个组数(def)的
      长度)
      A[3]=xyz 则是将第四个组数重新定义为 xyz ...
      
      最后为大家介绍 $(( )) 的用途吧:它是用来作整数运算的。
      在 bash 中,$(( )) 的整数运算符号大致有这些:
      + - * / :分别为 "加、减、乘、除"。
      % :余数运算
      & | ^ !:分别为 "AND、OR、XOR、NOT" 运算。
      例:
      代码:
      $ a=5; b=7; c=2
      $ echo $(( a+b*c ))
      19
      $ echo $(( (a+b)/c ))
      6
      $ echo $(( (a*b)%c))
      1
      事实上,单纯用 (( )) 也可重定义变量值,或作 testing:
      a=5; ((a++)) 可将 $a 重定义为 6
      a=5; ((a--)) 则为 a=4
      a=5; b=7; ((a < b)) 会得到 0 (true) 的返回值。
      常见的用于 (( )) 的测试符号有如下这些:
      :大于
      =:大于或等于
      ==:等于
      !=:不等于
      
      16. $@  与 $* 差在哪?
      在 shell script 中,我们可用 $0, $1, $2, $3 ... 这样的变量分别提取命令行中的如下部份:
      script_name parameter1 parameter2 parameter3 ...
      function 一样可以读取自己的(有别于 script 的) postitional parameter ,惟一例外
      的是 $0 而已。
      举例而言:假设 my.sh 里有一个 fucntion 叫 my_fun , 若在 script 中跑 my_fun fp1 fp2 fp3 ,那么,function 内的 $0 是 my.sh ,而 $1 则是 fp1 而非 p1 了...
      #!/bin/bash
      my_fun() {
      echo '$0 inside function is '$0
      echo '$1 inside function is '$1
      echo '$2 inside function is '$2
      }
      echo '$0 outside function is '$0
      echo '$1 outside function is '$1
      echo '$2 outside function is '$2
      my_fun fp1 &quot;fp2 fp3&quot;
      然后在 command line 中跑一下 script ,结果如下
      chmod +x my.sh
      ./my.sh p1 &quot;p2 p3&quot;
      $0 outside function is ./my.sh
      $1 outside function is p1
      $2 outside function is p2 p3
      $0 inside function is ./my.sh
      $1 inside function is fp1
      $2 inside function is fp2 fp3
      然而,在使用 positional parameter 的时候,我们要注意一些陷阱哦:
      * $10 不是替换第 10 个参数,而是替换第一个参数($1)然后再补一个 0 于其后﹗
      也就是,my.sh one two three four five six seven eigth nine ten 这样的 command
      line ,  my.sh 里的 $10 不是 ten 而是 one0 哦.
      要抓到 ten 的话,有两种方法:
      方法一是使用我们上一章介绍的 ${ } ,也就是用 ${10} 即可。
      方法二,就是 shift 了。
      用通俗的说法来说,所谓的 shift 就是取消位置参数中最左边的参数( $0 不
      受影响)。
      其默认值为 1 ,也就是 shift 或 shift 1 都是取消 $1 ,而原本的 $2 则变成 $1、$3 变
      成 $2 ...
      若 shift 3 则是取消前面三个参数,也就是原本的 $4 将变成 $1 ...
      那,亲爱的读者,你说要 shift 掉多少个参数,才可用 $1 取得 ${10} 呢? ^_^
      因此,我们常在 shell script 里用如下方法测试 script 是否有读进参数:
      代码:
      [ $# = 0 ]
      假如为 0 ,那就表示 script 没有参数,否则就是有带参数...
      接下来就是 $@ 与 $* :
      精确来讲,两者只有在 soft quote 中才有差异,否则,都表示&quot;全部参数&quot;( $0 除外)。
      举例来说好了:
      若在 command line 上跑 my.sh p1 &quot;p2 p3&quot; p4 的话,
      不管是 $@ 还是 $* ,都可得到 p1 p2 p3 p4 就是了。
      但是,如果置于 soft quote 中的话:
      &quot;$@&quot; 则可得到 &quot;p1&quot; &quot;p2 p3&quot; &quot;p4&quot; 这三个不同的词段(word)﹔
      &quot;$*&quot; 则可得到 &quot;p1 p2 p3 p4&quot; 这一整串单一的词段。
      #!/bin/bash
      my_fun() {
      echo &quot;$#&quot;
      }
      echo 'the number of parameter in &quot;$@&quot; is '$(my_fun &quot;$@&quot;)
      echo 'the number of parameter in &quot;$*&quot; is '$(my_fun &quot;$*&quot;)
      后再执行 ./my.sh p1 &quot;p2 p3&quot; p4 就知道 $@ 与 $* 差在哪了 ... ^_^
      
      16.   return value(RV)
      Return Value(RV) 的取值为 0-255 之间,由程序(或 script)的作者自行定议:
      * 若在 script 里, 用 exit RV 来指定其值,若没指定,在结束时以最后一道命令之 RV 为值。
      * 若在 function 里,则用 return RV 来代替 exit RV 即可。
      bash 的 test 目前支持的测试对像只有三种:
      以 A=123 这个变量为例
      * [ &quot;$A&quot; = 123 ]:是字符串的测试,以测试 $A 是否为 1、2、3 这三个连续的&quot;文字
      * [ &quot;$A&quot; -eq 123 ]:是整数的测试,以测试 $A 是否等于&quot;一百二十三&quot;。
      * [ -e &quot;$A&quot; ]:是关于文件的测试,以测试 123 这份&quot;文件&quot;是否存在。
      代码:
      $ unset A
      $ [ $A = abc ]
      [: =: unary operator expected
      
      16.     && 与 || 都是用来&quot;组建&quot;多个 command line 用的:
      * command1 && command2 :其意思是 command2 只有在 RV 为 0 (true) 的条件
      执行。
      * command1 || command2 :其意思是 command2 只有在 RV 为非 0 (false) 的条件
      下执行。
      $ A=123
      $ [ -n &quot;$A&quot; ] && echo &quot;yes! it's ture.&quot;
      yes! it's ture.
      $ unset A
      $ [ -n &quot;$A&quot; ] && echo &quot;yes! it's ture.&quot;
      $ [ -n &quot;$A&quot; ] || echo &quot;no, it's NOT ture.&quot;
      no, it's NOT ture.
      (注:[ -n string ] 是测试 string 长度大于 0 则为 true 。)
      上例的第一个 && 命令行之所以会执行其右边的 echo 命令,是因为上一个 test 送回了
      的 RV 值﹔
      但第二次就不会执行,因为为 test 送回非 0 的结果...
      同理,|| 右边的 echo 会被执行,却正是因为左边的 test 送回非 0 所引起的。
      事实上,我们在同一命令行中,可用多个 && 或 || 来组建呢:
      代码:
      $ A=123
      $ [ -n &quot;$A&quot; ] && echo &quot;yes! it's ture.&quot; || echo &quot;no, it's NOT ture.&quot;
      yes! it's ture.
      $ unset A
      $ [ -n &quot;$A&quot; ] && echo &quot;yes! it's ture.&quot; || echo &quot;no, it's NOT ture.&quot;
      no, it's NOT ture.
      
      下面的判断是:当 $A 被赋与值时,再看是否小于 100 ,否则送出 too big! :
      $ A=123
      $ [ -n &quot;$A&quot; ] && [ &quot;$A&quot; -lt 100 ] || echo 'too big!'
      too big!
      若我将 A 取消,照理说,应该不会送文字才对啊(因为第一个条件就不成立了)...
      $ unset A
      $ [ -n &quot;$A&quot; ] && [ &quot;$A&quot; -lt 100 ] || echo 'too big!'
      too big!
      


  • 运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
    2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
    3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
    4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
    5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
    6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
    7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
    8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

    所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-555862-1-1.html 上篇帖子: shell 之 算术运算 下篇帖子: shell 日期操作
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    扫码加入运维网微信交流群X

    扫码加入运维网微信交流群

    扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

    扫描微信二维码查看详情

    客服E-mail:kefu@iyunv.com 客服QQ:1061981298


    QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


    提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


    本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



    合作伙伴: 青云cloud

    快速回复 返回顶部 返回列表