【问题标题】:Using "declare" in Zsh在 Zsh 中使用“声明”
【发布时间】:2019-04-10 14:43:08
【问题描述】:

我正在关注这个帖子:https://stackoverflow.com/a/19742842/5057251 用于 ZSH 中的排版(或声明),而不是 BASH。

#Declare (or typeset) an array of integers
#declare -ai int_array
typeset -ai int_array
int_array=(1 2 3)
echo "${int_array[@]}"

然后

# Attempt to change 1st element to string. (expect to fail)
int_array[1]="Should fail" || echo "error: ${LINENO}"
echo "${int_array[@]}"

Bash 发现错误,优雅地报告错误和 lineno,打印:

1 2 3

但是 Zsh 接受,打印:

Should fail 2 3

不知道为什么不同。

【问题讨论】:

    标签: zsh


    【解决方案1】:

    这里有两个问题:

    1. 在 bash 和 zsh 中,将字符串分配给整数变量会导致该字符串被计算为算术表达式。因此,这不是错误:

      $ typeset -i foo
      $ foo="bar"
      

      如果 bar 是先前设置为算术表达式的变量,则 bar 的扩展将被计算为:

      $ bar=10+2
      $ typeset -i foo
      $ foo="bar"
      $ echo "$foo"
      12
      

      当然,您的作业中的错误是无法像那样扩展Should fail。例如,如果是Should - fail(一个算术表达式减去Shouldfail 两个变量的值,它仍然可以工作:

      $ foo="Should - fail"
      $ echo "$foo"
      0
      
    2. 第二个问题是the zsh docs 中没有任何内容表明可以为整个数组设置-i,因此-ai 中的-a 被忽略:

      bash-5.0$ typeset -ai foo
      bash-5.0$ declare -p foo
      declare -ai foo=([0]="0")  # the previous value was retained in the array
      

      vs zsh:

      % typeset -ai foo
      % foo[1]=10
      % foo[2]=20
      % declare -p foo
      typeset -i foo=20  # treated as a normal variable, not array
      

      当您执行 int_array=(1 2 3) 时,您所看到的基本上是 int_array 被重新声明为一个数组(没有任何限定符):

      % foo=(1 2 3)
      % declare -p foo
      typeset -a foo=( 1 2 3 )
      

    【讨论】:

    • 棘手。 declare -p foo # 非常有助于了解 shell 的想法
    【解决方案2】:

    使用 zsh 排版可以产生一些可能的结果:
    - 没有错误,有效(是的!)。
    - 错误,脚本失败(修复!)。
    - 没有错误,但有意外行为。 (抓头)

    作为最后一个类别的示例,这不会产生错误,但 typeset -p 显示 -i 被忽略。

    {                                                                                                                                                                        
    unset int_array                                                                                                                                                          
    typeset -ia int_array                                                                                                                                                    
    int_array=(1 2 3)                                                                                                                                                        
    echo $? "-Point A"                                                                                                                                                       
    typeset -p int_array                                                                                                                                                     
    
        } always {                                                                                                                                                           
    
    echo $? "-Point B"                                                                                                                                                       
    typeset -p int_array                                                                                                                                                     
    (( TRY_BLOCK_ERROR=0 ))                                                                                                                                                  
    }                                                                                                                                                                        
    echo $? "-Point C"                                                                                                                                                       
    echo "survived"                                                                                                                                                          
    

    产生

     0 -Point A                                                                                                                                                               
     typeset -a int_array=( 1 2 3 )                                                                                                                                           
     0 -Point B                                                                                                                                                               
     typeset -a int_array=( 1 2 3 )                                                                                                                                           
     0 -Point C                                                                                                                                                               
     survived                                                                                                                                                                 
    

    第一行取消设置 int_array。排版命令声明
    int_array 既是数组又是 int,这不是 zsh 允许的。下一个
    行将 int_array 分配给一个值。 $? 告诉我们没有错误,
    但仔细检查最终的 typeset -p int_array 揭示了实际情况
    发生了。

    稍作改动,我们就可以产生错误并使用always 块和
    typeset -p 查找更多详细信息。

    {                                                                                                                                                                        
    unset int_array                                                                                                                                                          
    typeset -ia int_array=(1 2 3) # error                                                                                                                                    
    echo $? "-Point A"                                                                                                                                                       
    typeset -p int_array 
    
          } always {                                                                                                                                                           
    
    echo $? "-Point B"                                                                                                                                                       
    typeset -p int_array                                                                                                                                                     
    (( TRY_BLOCK_ERROR=0 ))                                                                                                                                                  
    }                                                                                                                                                                        
    echo $? "-Point C"                                                                                                                                                       
    echo "survived"                                                                                                                                                          
    
    040_declare_version2.sh:typeset:135: int_array: inconsistent type for assignment                                                                                         
    1 -Point B                                                                                                                                                               
    040_declare_version2.sh:typeset:140: no such variable: int_array                                                                                                         
    1 -Point C                                                                                                                                                               
    survived                                                                                                                                                                 
    

    唯一的区别是 int_array 在错误的typeset -ia 语句中被赋予了一个值。
    这会产生错误,并且脚本会跳转到always block.
    (( TRY_BLOCK_ERROR=0)) 允许脚本继续
    并没有终止,但是在“C点”仍然报错。

    查看shell版本:

    $SHELL --version                                                                                                                                                         
    zsh 5.4.2 (x86_64-ubuntu-linux-gnu)                                                                                                                                      
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多