【问题标题】:Sequences expansion and variable in bash [duplicate]bash中的序列扩展和变量[重复]
【发布时间】:2011-02-10 11:36:38
【问题描述】:

当 seq 编号是变量时,我在 Bash 中遇到了内置序列(即:不使用 seq)的问题。例如,这有效并打印我 1 2 3:

for i in {1..3};do
  echo $i
done

但是这个:

a=3
for i in {1..$a};do
   echo $i
done 

失败并仅打印我 {1..3}

这适用于 ZSH,我知道我有另一种方法来制作计数器,但想知道这是错误还是大括号扩展功能!

【问题讨论】:

标签: bash expansion


【解决方案1】:

在 Bash 中,大括号扩展是在变量扩展之前执行的。订单见Shell Expansions

$ a=7; echo {1..3} {4..$a}
1 2 3 {4..7}

如果您想使用变量,请使用 C 风格的 for 循环,如 Shawn 的回答。

【讨论】:

    【解决方案2】:

    另一种方法是使用允许 C 样式循环的双括号结构:

    A=3
    for (( i=1; i<=$A; i++ )); do
        echo $i
    done
    

    【讨论】:

    • 嗨,我对使用外部命令不感兴趣,而是使用内置 bash。
    • 他不想用seq
    • 抱歉,错过了。更新了答案。
    【解决方案3】:
    $ num=3
    $ for i in $( eval echo {1..$num});do echo $i;done
    1
    2
    3
    

    【讨论】:

    • 对我来说有点像黑客...但是谢谢..
    • 效率低于 C 样式循环(由于使用子 shell)并且存在安全风险:请勿使用 eval,除非您完全控制或验证了传递给eval 的字符串。否则,可能会执行任意命令。例如,以下精心设计的 $num 值将枚举当前用户主文件夹中的文件:num='};ls ~;{'; for i in $(eval echo {1..$num});do echo $i;done
    【解决方案4】:
        #!/bin/bash - see comment for list of obsolete bash constructs
        function f_over_range {
            for i in $(eval echo {$1..$2}); do
                f $i
            done
        }
    
        function f {
            echo $1
        }
    
        #POSIX-compliant
        f_over_range() {
            for i in $(eval echo {$1..$2}); do
                f $i
            done
        }
    
        f() {
            echo $1
        }
    
    
        f_over_range 0 5
        f_over_range 00 05
    

    注意事项:

    • 使用 eval 会暴露命令注入安全风险
    • Linux 将打印“00\n01\n02..etc”,但 OSX 将打印“0\n1\n2\n...etc”
    • 使用 seq 或 C 样式的 for 循环与大括号扩展对前导零的处理不匹配

    【讨论】:

    • 我可以建议使用符合 POSIX 的函数声明语法吗?请参阅wiki.bash-hackers.org/scripting/obsolete -- function f { 是由于遗留原因而支持的 ksh-ism。
    • 链接的文档对我来说有点模棱两可。第一个表推荐替换NAME() COMPOUND-CMD or function NAME { CMDS; },而第三个表推荐替换NAME() COMPOUND-CMD。我根据TLDP 和我的解释更新了我的答案。
    • Granted -- 混合 POSIX 和 ksh 语法比使用 ksh 语法更糟糕,因为它会导致代码甚至与 ksh 不兼容,因此这种混合是链接文档最强烈地试图警告某人的事情。也就是说,ABS 作为不良实践示例的来源有点臭名昭著。
    • 请参阅wooledge.org/~greybot/meta/abs 在 freenode #bash 频道中跟踪 ABS factoid 的历史(第一列是每次更改的 seconds-since-epoch 时间戳),以及stackoverflow.com/tags/bash/info,在撰写本文时,其推荐来源中根本没有 ABS。
    【解决方案5】:

    其他选项是使用 seq 命令:

    a=3; for i in $(seq 1 $a);do echo $i;done
    

    【讨论】:

    • 由于使用了外部实用程序,效率不高,但它很简单,而且很有效。
    【解决方案6】:

    我还需要做一些类似的事情:

    n=某个数字; {1..$n..增量}

    所以我使用了这个解决方法:

    n=100  
    i=1
    while [ $i -lt $n ]
    do
    echo $i
    i=$(( $i+1 ))
    done
    

    【讨论】:

      【解决方案7】:

      试试这个:

      $ start=3
      $ end=5
      $ echo {$(echo $start)..$(echo $end)}
      

      【讨论】:

      • 打印以下 literal{3..5},这显然不是本意。如果您点击已接受答案中的链接,您将看到大括号扩展 ({...}) 发生在 命令替换 ($(...)) 之前,这就是您的方法无法工作的原因(在 Bash,已标记;它可以在 Ksh 和 Zsh 中工作,但无论如何您都可以在大括号扩展中直接使用变量,因此您只需使用start=3 end=5; echo {$start..$end}).
      • 对不起,我弄错了,echo {$(echo $start)..$(echo $end)} 不起作用,但 {$start,$end} 输出“3 5”。
      • 是的,确实如此,但这是大括号扩展的 list 形式(,-分隔项),而 OP 正在寻找的是 sequence (范围)形式(..)。具体来说:不是3 5,而是3 4 5
      猜你喜欢
      • 1970-01-01
      • 2013-09-29
      • 2015-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-28
      • 1970-01-01
      相关资源
      最近更新 更多