bash4.4参数--翻译自bash手册

本文深入解析Bash环境下的参数概念,包括变量赋值、扩展、特殊参数等,并通过实例演示了nameref属性的使用方法。

bash参数(此处的参数是指Bash环境的参数,并不是shell脚本参数或者函数参数)

参数可以是一个保存值的实体。参数可以是name、number、special characters。一个变量是用name表示的parameter。var具有值和0或多个属性。属性可以使用declare等这些内建的命令来赋予。


当一个parameter具有值的时候,就被设置了。null string也是一个合法的value。一旦var被set,那么必须使用unset这个内建命令才能消除。

使用如下形式的语句里赋值:

name=[value]  #这里的value回被各种扩展,name表示一个Parameter。

如果没有value,那么var的值就是null string。所有的value都要经过tilde expansion(波浪号扩展)、parameter and variable expansion、command substitution(命令替换)、arithmetic expansion(算术扩展)、quote removal(标记删除)等。如果一个var具有integer属性,那么即使没有使用$((...))表达式,value也会进行arthmetic expansion(算术扩展)。除了下面列出的$@之外,其他任何标记都不会执行word spliting。并且,filename expansion也不会被执行。赋值语句可以作为alias,declare,typeset,export,readonly和local等内建命令的参数。在上下文中,可以自动推断赋值语句的应该使用何种扩展。


另外,一个变量可以被赋予nameref属性,(这个属性相当于c++的refer,有 点类似于变量的别名),可以使用declare或local命令来声明一个nameref属性的变量。具有nameref属性的变量可以绑定到一个变量。对nameref变量的操作就相当于直接对绑定的变量进行操作。这个特性往往用来在shell function内部用于对参数变量进行操作。例如:

在shell function内部使用如下语句

declare -n ref=$1  #相当于ref与第一个参数进行绑定,但是第一个参数要采用变量的形式输入

正确使用如下所示:

  test(){
      declare -n ref=$1
      echo "ref=$ref"
      ref=1999999
      echo "after change,ref=$ref"
      echo $1
  }
  
  var1=11111111111
  echo "var=$var1"
  test var1
  echo "after change var=$var1" 

结果如下:

var=11111111111
ref=11111111111
after change,ref=1999999
var1
after change var=1999999

可以看到对于ref的更改导致了var1的更改,这说明如果需要再shell function内部对于外部变量进行更改的时候,可以使用nameref属性,就相当于c++的refer特性一样。

当在for循环中(这种形式:for ref in words),一个control variable如果具有了nameref属性,那么当for循环执行的时候,就会轮流的为words列表中的每一个word建立nameref绑定,注意words列表中的word必须是variable变量,如果是常亮,则可能会造成无法ref到该常亮上,通过以下几个例子来搞清楚如何使用这种特性:

例1:

  1 words="a b c d"
  2 declare -n ref
  3            
  4 for ref in words
  5 do         
  6     echo $ref
  7 done       
  8 echo $words  

结果如下:

a b c d
a b c d

我们看到ref正确指向了words变量。因为words在for语句执行时,其实一个变量,被ref正确的绑定了nameref关系。

例2

  1 words="a b c d"
  2 declare -n ref
  3  
  4 for ref in words
  5 do
  6     echo $ref
  7     ref="ddddddddddddd"
  8 done
  9 echo $words 

结果如下:

a b c d
ddddddddddddd

我们看到ref正确的与words建立了nameref属性,同时,通过更改ref的值,更改了words的值,符合nameref的特性。

例3

  1 words="a b c d"
  2 declare -n ref
  3  
  4 for ref in $words  #此处在执行时候,会先进行扩展,把$words替换成"a b c d",就相当于for ref in "a b c d","a b c d"就是相当于常亮
  5 do
  6     echo $ref                                                    
  7 done
  8 echo $words

结果如下:

a b c d

我们看到结果中前面对ref的输出都是成为了空格,这说明当in后面的列表是常亮的时候,ref并不能正确的建立nameref属性到其身上,最终导致了ref没有变量绑定,从而输出了空格。


而bash内置了一些特殊的内部parameter

第一类:positional parameters

$0,$1,$2....$n

其中$0是指得脚本本身(在执行脚本的时候,$0=脚本本身,当在shell中的时候,$0=shell名),相当于c语言中的arg0。与此相关的两个命令set和shift可以用来撤销这些变量。具体可见shell脚本参数的使用。当N大于等于10的时候,需要使用如下形式${10}。

$1,$2...$n分别指向第一个参数,第二个参数。。。。最后一个参数

第二类:special parameters


* 使用$*,其会扩展成位置参数,从第一个位置参数开始。如果是直接使用$*,也就是说扩展的时候没有双引号,那么每一个位置参数就会直接扩展成相应的分离的word。如果扩展的时候存在双引号,则在双引号内,就会根据一个分隔符来进行word的切分,通常这个分隔符都是空格space。


@使用$@,其会扩展成位置参数,从第一个位置参数开始。当扩展发生在双引号内,每个参数都会成为一个独立的word。"$@"就相当于"$1","$2","$3"....。


#使用$#,扩展成位置参数的个数,十进制表示


?使用$?,扩展成上一条命令的exit status,即上一条命令的退出状态


-使用$-,扩展成set设置的选项,或者shell自身的选项属性


$使用$$,扩展成shell的PID,这个PID是指得是调用$$这个命令的那个shell。所以当脚本嵌套调用的时候,要注意子shell和父shell,如果是在父shell调用echo $$,则输出的是父shell的PID;如果是在子shell中调用echo $$,则输出的是子shell的PID。


!使用$!,扩展成上一次启动的后台任务的pid


0使用$0,扩展成shell名或者脚本名。$0直接在shell中执行,则扩展成当前shell名,如bash。如果是在脚本中运行,则扩展成脚本名。



_使用$_,该变量扩展成上一条命令的最后一个参数(当某个命令没有参数时,就扩展成其自身(相当于参数arg[0]))。有几种情况需要注意:当产生一个新的shell时,该变量依然会扩展成the last command's last arg.但是当产生一个新的shell的时,由于其会读取一些配置文件,如~/.bashrc等,所以,会扩展成这些配置文件的最后一行的一个参数。当产生一个执行脚本的子shell时,其一开始扩展成为shell脚本的的名字,如执行./test.sh,那么在子shell中首先$_=./test.sh,后面依然会扩展成上一次执行命令的最后一个参数。在处理邮件时,会扩展成邮件的文件名。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值