bash 带变量的支撑扩展?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19432753/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 08:20:20  来源:igfitidea点击:

Brace expansion with variable?

bashvariablessyntaxvariable-expansion

提问by mklement0

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

Would work, displays Welcome 5 times.

会工作,显示欢迎 5 次。

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

Doesn't work! howmanywould equal 5 as that is what the output of grep -cwould display. $1 is parameter 1 which is specific when running the script.

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

Any ideas?

有任何想法吗?

采纳答案by Luis Mu?oz

create a sequence to control your loop

创建一个序列来控制你的循环

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

回答by mklement0

Workaroundsfor not being able to use variables in a sequence brace expression:

无法在序列大括号表达式中使用变量的解决方法

  • If the intent is merely to iterate over numbers in a range- as in the OP's case - the best choice is notto use brace expansion, but instead use bash's C-style loop- see user000001's answer.

    • If the specific numbers aren't important and you simply need to execute a loop body a specified number of times, Cole Tierney's answeris an option.
  • If use of brace expansion isdesired nonetheless:

    • If you do NOT need the numbers in the list to have a prefix or postfix, use the sequtility with an unquotedcommand substitution (small caveat: seqis NOT a POSIX utility, but it is widely available); e.g.

      • echo $(seq 3)-> 1 2 3; start number 1implied
        • echo $(seq -f '%02.f' 3)-> 01 02 03- zero-padded
      • echo $(seq 2 4)-> 2 3 4; explicit start and end numbers
      • echo $(seq 1 2 5)-> 1 3 5; custom increment (the 2in the middle)
    • If you DO need the numbers in the list to have a prefix or postfix, you have several choices:

      • Use the sequtility with its -foption for providing a printf-style format string (as used above for zero-padding), or pure Bash workarounds based on eval(extra care needed!) or building an arrayin a loop, all of which are detailed in this answer.
      • You could also consider implementing the functionality generically, such as by writing a custom shell function or a custom script with utilities such as awkor perl.
  • 如果目的只是迭代范围内的数字- 如在 OP 的情况下 -最好的选择不是使用大括号扩展,而是使用 bash 的C 样式循环- 请参阅user000001's answer

    • 如果特定数字不重要,而您只需要执行指定次数的循环体,则Cole Tierney 的答案是一个选项。
  • 如果使用大括号展开的仍然期望:

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

      • 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- 样式格式字符串(如上面用于零填充),或基于eval(需要额外小心!)或在循环中构建数组的纯 Bash 解决方法,所有这些都在详述回答
      • 您还可以考虑通用地实现该功能,例如通过编写自定义 shell 函数或使用实用程序(如awk或 )编写自定义脚本perl

Example of safe use of evalwith variables driving a sequence brace expression:

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

The variables are validated beforehand, to make sure they contain decimal integers.

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

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'

General overview of brace expansion

大括号扩展概述

The main purpose of brace expansionis to expand to a list of tokenswith each token having an optional prefix and/or postfix; brace expansions must be unquotedand come in 2 flavors:

大括号扩展主要目的扩展到一个标记列表,每个标记都有一个可选的前缀和/或后缀;大括号扩展必须不加引号,并且有2 种风格

  • a fixed series(list) of comma-separated strings- variables supported
    • specifies and expands to a fixednumber of tokens(2 or more); e.g.:
    • echo A{b,c,d}-> Ab Ac Ad, i.e., 3 tokens, as implied by the number of args.
    • echo {/,$HOME/}Librarye.g., -> /Library /User/jdoe/Library
    • Variable references - and even globs - aresupported, but note that they get expanded afterbrace expansion, in its result, in the course of normal evaluation.
  • a sequenceexpression (range) with .., typicallynumerical- variables NOT supported

    • expands to a variablenumber of tokens, driven by literalstart and end points(for historical reasons, use of variables is NOT supported- see the comments on user000001's answer):
      • [rare] strings: only single English lettersallowed; e.g. {a..c}
      • numbers: decimal integers only; e.g., {1..10}, {10..1}, {-1..2}
        • example with prefix and postfix: A{1..3}#-> A1# A2# A3#
        • brokenexample with variables: {$from..$to} # !! FAILS- $fromand $toare interpreted as literalsand therefore not recognized as either a single letter or a decimal integer - nobrace expansion is performed (see below).
          • by contrast, using variables doeswork in zshand ksh.
      • bash 4+adds two features:
        • optional increment step value:
          • echo A{1..5..2}-> A1 A3 A5- numbers incremented by 2
        • ability to zero-pad:
          • echo A{001..003}-> A001 A002 A003
  • An invalidbrace expressionis notexpanded(treated like a regular unquoted string, with {and }treated as literals):

    • echo {}-> '{}'- invalid as a brace expr.: at least 2,-separated tokens needed
      • This allows the use of unquoted {}with find, for instance.
    • echo {1..$to}-> '{1..<value-of-$to>}'- invalid as a brace expr. in bash: variables not supported; however, validin kshand zsh.
    • (fish, by contrast, expands any{...}sequence; similarly, zshhas option BRACE_CCL(OFF by default) for expanding individualcharacters inside {..}, which effectively causes expansion of any nonempty{...}sequence.)
  • 逗号分隔的字符串固定系列(列表)-支持变量
    • 指定并扩展到固定数量的令牌(2 个或更多);例如:
    • echo A{b,c,d}-> Ab Ac Ad,即 3 个标记,正如 args 的数量所暗示的那样。
    • echo {/,$HOME/}Library例如,-> /Library /User/jdoe/Library
    • 变量引用-甚至水珠-都是支持的,但请注意,得到扩展括号扩展,其结果,在正常评价的过程。
  • 一个序列表达式(范围)..通常是数字-不支持变量

    • 扩展为可变数量的令牌,由文字开始和结束点驱动(由于历史原因不支持使用变量- 请参阅关于user000001 的回答的评论):
      • [稀有]字符串:只允许单个英文字母;例如{a..c}
      • 数字仅限十进制整数;例如, {1..10}, {10..1},{-1..2}
        • 带有前缀和后缀的示例:A{1..3}#->A1# A2# A3#
        • 带有变量的损坏示例:{$from..$to} # !! FAILS-$from并被$to解释为文字,因此不被识别为单个字母或十进制整数 -执行大括号扩展(见下文)。
          • 相比之下,使用变量确实适用于zshksh
      • bash 4+添加了两个功能:
        • 可选的增量步长值
          • echo A{1..5..2}-> A1 A3 A5- 数字增加 2
        • 零填充能力:
          • echo A{001..003}-> A001 A002 A003
  • 一个无效支架表达膨胀(像普通的未引用的字符串处理,用{}作为处理文字):

    • echo {}-> '{}'- 作为大括号表达式无效:至少需要2 个 -,分隔的标记
      • 例如,这允许使用不带引号的{}with find
    • echo {1..$to}-> '{1..<value-of-$to>}'- 作为大括号 expr 无效。in bash: 不支持变量;但是,在和 中有效kshzsh
    • fish相比之下,扩展任何{...}序列;类似地,zsh具有BRACE_CCL扩展内部单个字符的选项(默认情况下关闭){..},这有效地导致任何非空{...}序列的扩展。)

回答by user000001

The brace expansion is evaluated before the variables are expanded. You need a c-style for loop instead:

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

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

回答by tolanj

The problem is that the "brace expansion" is performed before the "variable expansion"

问题是“大括号扩展”是在“变量扩展”之前执行的

for i in $(seq 1 $howmany) 

works as @damienfrancois said, or, if you would like:

像@damienfrancois 所说的那样工作,或者,如果您愿意:

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

probably does, but don't use it for everyone's sanity.

可能会,但不要为了每个人的理智而使用它。

回答by Cole Tierney

You could also use a while loop:

您还可以使用 while 循环:

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

回答by codeforester

We could also use evalin this case:

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

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