【问题标题】:shell - put variable in ALPHABETICAL range of cycleshell - 将变量放在循环的 ALPHABETICAL 范围内
【发布时间】:2014-09-06 16:58:12
【问题描述】:

有没有办法把变量放在循环的字母范围内? 这不起作用。

read -p "Where I should start?" start #there will be entered one small letter
for aaa in {$start..z}; do #how put variable $start in range?
...
done

感谢回复。

【问题讨论】:

    标签: bash variables range alphabetical


    【解决方案1】:

    使用eval扩展变量:

    $ s=t
    $ eval echo {$s..z}
    t u v w x y z
    

    你的例子就变成了:

    read -p "Where I should start?" start #there will be entered one small letter
    for aaa in $(eval echo {$start..z}); do 
    echo $aaa
    done
    

    由于您有eval 的用户输入,您可能需要先检查 start 的值是否为单个小写字符:

    read -p "Where I should start?" start #there will be entered one small letter
    if [[ $start =~ ^[a-y]$ ]]; then 
       for aaa in $(eval echo {$start..z}); do 
       echo $aaa
       done
    else 
       echo "Need to use a letter 'a-y'"
    fi
    

    您可以阅读有关 Bash 大括号扩展的更多信息 here

    【讨论】:

    • 你为什么要做这么简单的事情? ;)
    【解决方案2】:

    很遗憾,您不能将变量放在 bash 中的 {start..end} 范围内。

    这就是你想要的:

    until [[ $s == "_" ]]; do echo $s && s=$(tr "a-z" "b-z_" <<<$s); done
    

    它使用tr 将每个字符转换为下一个字符。 “_”是“z”后面的字符。

    例如:

    $ s=t
    $ until [[ $s == "_" ]]; do echo $s && s=$(tr "a-z" "b-z_" <<<$s); done
    t
    u
    v
    w
    x
    y
    z
    

    如果你不介意使用 Perl,你可以使用这个:

    perl -le 'print for shift .. "z"' $s
    

    它使用.. 在命令行的第一个参数和“z”之间创建一个列表。

    在 bash 中更深奥的方法是:

    for ((i=$(LC_CTYPE=C printf '%d' "'$s"); i<=122; ++i)); do 
        printf "\\$(printf '%03o' $i)\n" 
    done
    

    for 循环从变量 $s 的 ASCII 字符编号变为“z”,即 ASCII 字符 122。内部的格式说明符 printf 将字符编号转换为八进制,并用零填充最多三个字符。外部printf 然后将其解释为转义序列并打印字符。 感谢 Greg's wiki 用于将 ASCII 字符转换为其值的代码

    当然,您可以只使用eval 来扩展变量,这样做的好处是所需的代码要短得多。但是,执行已读入脚本的任意字符串可能存在安全漏洞。

    【讨论】:

      【解决方案3】:
      x=t
      for I in $(sed -nr "s/.*($x.*)/\1/;s/ /\n/g;p" <(echo {a..z}))
      do 
        # do something with $I
      done
      

      输出:

      吨 你 v w X 是的 z

      【讨论】:

        【解决方案4】:

        我会避免使用eval

        for aaa in {a..z}; do
            [[ $aaa < $start ]] && continue
            ...
        done
        

        比较$aaa$start 的开销应该可以忽略不计,尤其是与启动单独进程来计算范围的成本相比。

        【讨论】:

          猜你喜欢
          • 2013-02-25
          • 2016-01-24
          • 2016-01-14
          • 2012-06-12
          • 2014-11-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-10-16
          相关资源
          最近更新 更多