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
Brace expansion with variable?
提问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! 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.
不起作用!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
seq
utility with an unquotedcommand substitution (small caveat:seq
is NOT a POSIX utility, but it is widely available); e.g.echo $(seq 3)
->1 2 3
; start number1
impliedecho $(seq -f '%02.f' 3)
->01 02 03
- zero-padded
echo $(seq 2 4)
->2 3 4
; explicit start and end numbersecho $(seq 1 2 5)
->1 3 5
; custom increment (the2
in the middle)
If you DO need the numbers in the list to have a prefix or postfix, you have several choices:
- Use the
seq
utility with its-f
option for providing aprintf
-style format string (as used above for zero-padding), or pure Bash workarounds based oneval
(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
awk
orperl
.
- Use the
如果目的只是迭代范围内的数字- 如在 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
在中间)
如果您确实需要列表中的数字带有前缀或后缀,您有几种选择:
Example of safe use of eval
with variables driving a sequence brace expression:
安全使用eval
with 变量驱动序列大括号表达式的示例:
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/}Library
e.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
-$from
and$to
are 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
zsh
andksh
.
- by contrast, using variables doeswork in
- example with prefix and postfix:
- 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
- optional increment step value:
- [rare] strings: only single English lettersallowed; e.g.
- 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):
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
{}
withfind
, for instance.
- This allows the use of unquoted
echo {1..$to}
->'{1..<value-of-$to>}'
- invalid as a brace expr. inbash
: variables not supported; however, validinksh
andzsh
.- (
fish
, by contrast, expands any{...}
sequence; similarly,zsh
has optionBRACE_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
解释为文字,因此不被识别为单个字母或十进制整数 -不执行大括号扩展(见下文)。- 相比之下,使用变量确实适用于
zsh
和ksh
。
- 相比之下,使用变量确实适用于
- 带有前缀和后缀的示例:
- bash 4+添加了两个功能:
- 可选的增量步长值:
echo A{1..5..2}
->A1 A3 A5
- 数字增加 2
- 零填充能力:
echo A{001..003}
->A001 A002 A003
- 可选的增量步长值:
- [稀有]字符串:只允许单个英文字母;例如
- 扩展为可变数量的令牌,由文字开始和结束点驱动(由于历史原因,不支持使用变量- 请参阅关于user000001 的回答的评论):
一个无效支架表达是不膨胀(像普通的未引用的字符串处理,用
{
和}
作为处理文字):echo {}
->'{}'
- 作为大括号表达式无效:至少需要2 个 -,
分隔的标记- 例如,这允许使用不带引号的
{}
withfind
。
- 例如,这允许使用不带引号的
echo {1..$to}
->'{1..<value-of-$to>}'
- 作为大括号 expr 无效。inbash
: 不支持变量;但是,在和 中有效。ksh
zsh
- (
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 eval
in this case:
我们也可以eval
在这种情况下使用:
howmany=`grep -c /root/file`
for i in $(eval echo {1..$howmany}); do
echo "Welcome"
done