用变量支撑扩展?

时间:2013-10-17 16:54:24

标签: bash variables syntax variable-expansion

#!/bin/sh
for i in {1..5}
do
   echo "Welcome"
done

会工作,显示欢迎5次。

#!/bin/sh
howmany=`grep -c $1 /root/file`
for i in {1..$howmany}
do
   echo "Welcome"
done

不起作用! howmany等于5,因为grep -c的输出会显示。 $ 1是参数1,在运行脚本时是特定的。

有什么想法吗?

6 个答案:

答案 0 :(得分:15)

解决方法,因为无法在序列括号表达式中使用变量:

  • 如果意图仅仅是迭代范围内的数字 - 就像OP的情况一样 - 最佳选择来使用大括号扩展,而是使用bash的 C风格循环 - 请参阅user000001's answer

    • 如果具体数字不重要且您只需要执行指定次数的循环体,Cole Tierney's answer就是一个选项。
  • 如果仍然需要使用支撑扩展

    • 如果您不需要列表中的数字具有前缀或后缀 ,请使用 seq 带有未加引号命令替换的实用程序(小警告seq不是POSIX实用程序,但它可以广泛使用); e.g。

      • echo $(seq 3) - > 1 2 3;起始号码1 暗示
        • echo $(seq -f '%02.f' 3) - > 01 02 03 - 零填充
      • echo $(seq 2 4) - > 2 3 4;明确的开始和结束数字
      • echo $(seq 1 2 5) - > 1 3 5;自定义增量(中间的2
    • 如果您需要列表中的数字具有前缀或后缀 ,您有以下几种选择:

      • 使用seq实用程序及其-f选项提供printf样式格式字符串(如上面用于零填充)或基于{{1的纯Bash解决方法(需要特别小心!)或在循环中构建数组,所有这些都在this answer中详细说明。
      • 您还可以考虑一般性地实现该功能,例如编写自定义shell函数或使用evalawk等实用程序的自定义脚本。

使用驱动序列括号表达式的变量安全使用perl的示例:

预先验证变量,以确保它们包含十进制整数。

eval

支撑扩张的一般概述

大括号扩展的主要目的是扩展为令牌列表,每个令牌都有可选前缀和/或后缀;大括号扩展必须不加引号并进入 2种风格

  • 以逗号分隔的字符串的 固定系列(列表) - 变量支持
    • 指定并扩展为 已修复个令牌数(2个或更多); e.g:
    • from=1 to=3 # sample values # Ensure that $from and $to are decimal numbers and abort, if they are not. (( 10#$from + 10#$to || 1 )) 2>/dev/null || { echo "Need decimal integers" >&2; exit 1; } eval echo "A{$from..$to}" # -> 'A1 A2 A3' - > echo A{b,c,d},即3个令牌,如args的数量所暗示。
    • Ab Ac Ad例如 - > echo {/,$HOME/}Library
    • 支持变量引用 - 甚至是globs - ,但请注意,在结果中,大括号扩展后,它们会在结果中扩展正常评估过程。
  • 序列表达式(范围)/Library /User/jdoe/Library通常数字 - 变量不支持

    • 扩展为 变量令牌数,由 文字起点和终点驱动(适用于历史原因不支持使用变量 - 请参阅user000001's answer上的评论:
      • [稀有] 字符串:仅允许单个英文字母;例如..
      • 数字仅限十进制整数;例如,{a..c}{1..10}{10..1}
        • 带前缀和后缀的示例:{-1..2} - > A{1..3}#
        • 使用变量
        • 已损坏的示例:A1# A2# A3# - {$from..$to} # !! FAILS$from被解释为文字因此不会被识别为单个字母或十进制整数 - 没有大括号扩展(见下文)。
          • 相比之下,使用变量 $tozsh 中工作。
      • bash 4 + 添加了两项功能:
        • 可选增量步长值
          • ksh - > echo A{1..5..2} - 数字增加2
        • 零填充的能力:
          • A1 A3 A5 - > echo A{001..003}
  • 无效的大括号表达式 展开(被视为常规的不带引号的字符串, A001 A002 A003{被视为文字):

    • } - > echo {} - 作为大括号expr无效:至少 2 '{}' - 需要分开的标记
      • 例如,这允许使用不带引号的,{}
    • find - &gt; echo {1..$to} - 作为大括号expr无效。在'{1..<value-of-$to>}'中:不支持变量;但是,bashksh中的有效
    • (相比之下,zsh会扩展任何 fish序列;类似地,{...}具有选项zsh(默认为OFF)以进行扩展BRACE_CCL中的个别字符,有效地导致任何非空 {..}序列的扩展。)

答案 1 :(得分:12)

在扩展变量之前评估大括号扩展。你需要一个c风格的循环:

for ((i=1;i<=howmany;i++))
do
   echo "Welcome"
done

答案 2 :(得分:7)

创建一个控制循环的序列

for i in $(seq 1 $howmany); do
echo "Welcome";
done

答案 3 :(得分:6)

问题是“支撑扩展”是在“可变扩展”

之前执行的
for i in $(seq 1 $howmany) 

作为@damienfrancois说,或者,如果你愿意:

for i in $(eval echo '{$start..10}') 

可能会这样做,但不要将它用于每个人的理智。

答案 4 :(得分:5)

你也可以使用while循环:

while ((howmany--)); do
   echo "Welcome"
done

答案 5 :(得分:0)

在这种情况下我们也可以使用eval

howmany=`grep -c $1 /root/file`
for i in $(eval echo {1..$howmany}); do
    echo "Welcome"
done