用变量支撑扩展?

16 variables syntax bash variable-expansion

#!/bin/sh
for i in {1..5}
do
   echo "Welcome"
done
Run Code Online (Sandbox Code Playgroud)

会工作,显示欢迎5次.

#!/bin/sh
howmany=`grep -c $1 /root/file`
for i in {1..$howmany}
do
   echo "Welcome"
done
Run Code Online (Sandbox Code Playgroud)

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

Any ideas?

mkl*_*nt0 18

无法在序列括号表达式中使用变量的变通方法:

  • 如果意图只是迭代一个范围内的数字 - 如OP的情况 - 最好的选择不是使用大括号扩展,而是使用bash的C风格循环 - 请参阅user000001的答案.

    • 如果具体的数字并不重要,你只需要执行指定次数的循环体,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(特别小心需要!),或者建立一个阵列在一个循环中,所有这些都是在详细此回答.
      • 您还可以考虑一般性地实现该功能,例如通过编写自定义shell函数或使用诸如awk或等实用程序的自定义脚本perl.

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

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

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'
Run Code Online (Sandbox Code Playgroud)

支架扩展概述

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

  • 逗号分隔字符串固定系列(列表) - 支持的变量
    • 指定并扩展为固定数量的令牌(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 {}- > '{}'- 作为括号expr无效:至少需要2个 ,分隔的标记
      • 这允许使用不带引号的{}使用find,例如.
    • echo {1..$to}- > '{1..<value-of-$to>}'- 作为大括号expr无效.in bash:不支持的变量; 但是,在和中有效.kshzsh
    • (fish相反,扩展任何 {...}序列;类似地,zsh有选项BRACE_CCL(默认为OFF)用于扩展内部的单个字符{..},这有效地导致任何非空 {...}序列的扩展.)


use*_*001 14

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

for ((i=1;i<=howmany;i++))
do
   echo "Welcome"
done
Run Code Online (Sandbox Code Playgroud)

  • @Shahbaz可能,但是'bash`根本就没有.最初,支撑扩展设计用于像`a {b,c} d`这样扩展为`abd acd`的东西; `{1..10}`语法是后来添加的,但扩展顺序已经修复.我怀疑改变它以允许括号内的参数是不值得的.对于它的价值,`zsh`*确实*允许在扩展内扩展参数. (7认同)
  • @chepner:很高兴知道; 我首先感到困惑的是它_withes_使用_string-token list_形式的变量:`v1 = a v2 = b; echo {$ v1,$ v2}` - >`'a b'`.Bash _first_将其转换为令牌列表`"$ v1 $ v2"`(大括号扩展),_then_扩展变量引用(参数扩展),对吗?由于必须保留此扩展顺序以实现向后兼容,因此使用_numeric-range_形式中的变量不起作用,因为在不知道变量引用表示的数字的情况下,bash无法创建令牌列表,因为它不知道什么和有多少令牌创建. (2认同)

Lui*_*ñoz 7

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

for i in $(seq 1 $howmany); do
echo "Welcome";
done
Run Code Online (Sandbox Code Playgroud)

  • `seq`不是POSIX标准化工具.它不能保证在POSIX系统上完全安装,更不用说以任何特定方式运行. (5认同)

tol*_*anj 7

问题是"支撑扩展"是在"可变扩展"之前执行的

for i in $(seq 1 $howmany) 
Run Code Online (Sandbox Code Playgroud)

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

for i in $(eval echo '{$start..10}') 
Run Code Online (Sandbox Code Playgroud)

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


Col*_*ney 5

你也可以使用while循环:

while ((howmany--)); do
   echo "Welcome"
done
Run Code Online (Sandbox Code Playgroud)