在Bash中如何迭代由变量定义的一系列数字?

时间:2022-10-30 10:56:00

How do I iterate over a range of numbers in Bash when the range is given by a variable?

当一个变量给出范围时,如何在Bash中迭代一系列数字?

I know I can do this (called "sequence expression" in the Bash documentation):

我知道我可以这样做(在Bash文档中称为“序列表达式”):

 for i in {1..5}; do echo $i; done

Which gives:

这使:

1
2
3
4
5

1 2 3 4 5。

Yet, how can I replace either of the range endpoints with a variable? This doesn't work:

但是,我如何用变量替换任意一个范围端点呢?这并不工作:

END=5
for i in {1..$END}; do echo $i; done

Which prints:

打印:

{1..5}

{ 5 } 1 . .

17 个解决方案

#1


1106  

for i in $(seq 1 $END); do echo $i; done

edit: I prefer seq over the other methods because I can actually remember it ;)

编辑:我更喜欢seq,而不是其他方法,因为我实际上可以记住它;

#2


288  

The seq method is the simplest, but Bash has built-in arithmetic evaluation.

seq方法是最简单的,但是Bash有内置的算术计算。

END=5
for ((i=1;i<=END;i++)); do
    echo $i
done
# ==> outputs 1 2 3 4 5 on separate lines

The for ((expr1;expr2;expr3)); construct works just like for (expr1;expr2;expr3) in C and similar languages, and like other ((expr)) cases, Bash treats them as arithmetic.

为((expr1;expr2;expr3));在C语言和类似的语言中,构建工作就像(expr1;expr2;expr3),和其他(expr)的例子一样,Bash将它们视为算术。

#3


156  

discussion

Using seq is fine, as Jiaaro suggested. Pax Diablo suggested a Bash loop to avoid calling a subprocess, with the additional advantage of being more memory friendly if $END is too large. Zathrus spotted a typical bug in the loop implementation, and also hinted that since i is a text variable, continuous conversions to-and-fro numbers are performed with an associated slow-down.

正如Jiaaro所建议的,使用seq是可以的。Pax Diablo建议使用Bash循环来避免调用子进程,如果$END太大,则具有更多内存友好的额外优势。Zathrus在循环实现中发现了一个典型的bug,并且还暗示由于我是一个文本变量,所以连续的转换数字是通过一个相关的减速来执行的。

integer arithmetic

This is an improved version of the Bash loop:

这是Bash循环的改进版本:

typeset -i i END
let END=5 i=1
while ((i<=END)); do
    echo $i
    …
    let i++
done

If the only thing that we want is the echo, then we could write echo $((i++)).

如果我们想要的只是echo,那么我们可以写echo $((i++))。

ephemient taught me something: Bash allows for ((expr;expr;expr)) constructs. Since I've never read the whole man page for Bash (like I've done with the Korn shell (ksh) man page, and that was a long time ago), I missed that.

ephemient教会了我一些东西:Bash允许((expr;expr;expr))构造。因为我从来没有读过Bash的整个手册页(就像我用Korn shell (ksh)手册所做的那样,那是很久以前的事了),我错过了。

So,

所以,

typeset -i i END # Let's be explicit
for ((i=1;i<=END;++i)); do echo $i; done

seems to be the most memory-efficient way (it won't be necessary to allocate memory to consume seq's output, which could be a problem if END is very large), although probably not the “fastest”.

似乎是最有效的方法(不需要分配内存来消耗seq的输出,这可能是一个问题,如果结束非常大),尽管可能不是“最快的”。

the initial question

eschercycle noted that the {a..b} Bash notation works only with literals; true, accordingly to the Bash manual. One can overcome this obstacle with a single (internal) fork() without an exec() (as is the case with calling seq, which being another image requires a fork+exec):

eschercycle注意到{a.. ..b} Bash符号只适用于文字;确实,根据Bash手册。一个人可以用一个(内部)fork()来克服这个障碍,而没有exec()(就像调用seq的情况一样,这是另一个图像需要一个fork+exec):

for i in $(eval echo "{1..$END}"); do

Both eval and echo are Bash builtins, but a fork() is required for the command substitution (the $(…) construct).

eval和echo都是Bash builtins,但是命令替换需要一个fork()($(…)构造)。

#4


81  

Here is why the original expression didn't work.

这就是为什么最初的表达不起作用。

From man bash:

从人抨击:

Brace expansion is performed before any other expansions, and any characters special to other expansions are preserved in the result. It is strictly textual. Bash does not apply any syntactic interpretation to the context of the expansion or the text between the braces.

在任何其他扩展之前执行括号扩展,在结果中保留其他扩展的特殊字符。它是严格的文本。Bash不将任何语法解释应用到扩展的上下文或括号之间的文本。

So, brace expansion is something done early as a purely textual macro operation, before parameter expansion.

因此,在参数展开之前,先做一个纯文本的宏操作,这样做是很早就完成的。

Shells are highly optimized hybrids between macro processors and more formal programming languages. In order to optimize the typical use cases, the language is made rather more complex and some limitations are accepted.

shell是在宏处理器和更正式的编程语言之间高度优化的混合。为了优化典型的用例,语言变得更加复杂,一些限制被接受。

Recommendation

建议

I would suggest sticking with Posix1 features. This means using for i in <list>; do, if the list is already known, otherwise, use while or seq, as in:

我建议你坚持使用Posix1特性。这意味着在 中使用i;如果列表已知,则使用while或seq,如:

#!/bin/sh

limit=4

i=1; while [ $i -le $limit ]; do
  echo $i
  i=$(($i + 1))
done
# Or -----------------------
for i in $(seq 1 $limit); do
  echo $i
done


1. Bash is a great shell and I use it interactively, but I don't put bash-isms into my scripts. Scripts might need a faster shell, a more secure one, a more embedded-style one. They might need to run on whatever is installed as /bin/sh, and then there are all the usual pro-standards arguments. Remember shellshock, aka bashdoor?

#5


41  

The POSIX way

POSIX的方式

If you care about portability, use the example from the POSIX standard:

如果您关心可移植性,请使用POSIX标准中的示例:

i=2
end=5
while [ $i -le $end ]; do
    echo $i
    i=$(($i+1))
done

Output:

输出:

2
3
4
5

Things which are not POSIX:

不是POSIX的东西:

  • (( )) without dollar, although it is a common extension as mentioned by POSIX itself.
  • 没有美元,尽管它是POSIX本身所提到的公共扩展。
  • [[. [ is enough here. See also: What is the difference between single and double square brackets in Bash?
  • [[。(这里就足够了。参见:Bash中单个和双方括号的区别是什么?
  • for ((;;))
  • ((,))
  • seq (GNU Coreutils)
  • seq(GNU Coreutils)
  • {start..end}, and that cannot work with variables as mentioned by the Bash manual.
  • {开始. .end},并且不能使用Bash手册所提到的变量。
  • let i=i+1: POSIX 7 2. Shell Command Language does not contain the word let, and it fails on bash --posix 4.3.42
  • 让i=i+1: POSIX 7 2。Shell命令语言不包含let,并且在bash中失败——posix 4.3.42。
  • the dollar at i=$i+1 might be required, but I'm not sure. POSIX 7 2.6.4 Arithmetic Expansion says:

    i=$i+1的美元可能是需要的,但我不确定。POSIX 7 2.6.4算法扩展说:

    If the shell variable x contains a value that forms a valid integer constant, optionally including a leading plus or minus sign, then the arithmetic expansions "$((x))" and "$(($x))" shall return the same value.

    如果shell变量x包含一个值,该值形成一个有效的整数常量,可选地包括一个前置加号或减号,那么算术展开式“$(x)”和“$($x)”将返回相同的值。

    but reading it literally that does not imply that $((x+1)) expands since x+1 is not a variable.

    但是从字面上看,这并不意味着$((x+1))的扩展,因为x+1不是一个变量。

#6


28  

Another layer of indirection:

另一个间接层:

for i in $(eval echo {1..$END}); do
    ∶

#7


18  

If you're on BSD / OS X you can use jot instead of seq:

如果你在BSD / OS X上,你可以用jot代替seq:

for i in $(jot $END); do echo $i; done

#8


17  

You can use

您可以使用

for i in $(seq $END); do echo $i; done

#9


12  

This works fine in bash:

这在bash中很有效:

END=5
i=1 ; while [[ $i -le $END ]] ; do
    echo $i
    ((i = i + 1))
done

#10


8  

If you need it prefix than you might like this

如果你需要它的前缀,你可能会喜欢它。

 for ((i=7;i<=12;i++)); do echo `printf "%2.0d\n" $i |sed "s/ /0/"`;done

that will yield

这将产生

07
08
09
10
11
12

#11


6  

I know this question is about bash, but - just for the record - ksh93 is smarter and implements it as expected:

我知道这个问题是关于bash的,但是-仅仅为了记录- ksh93是更聪明的,并按照预期实现它:

$ ksh -c 'i=5; for x in {1..$i}; do echo "$x"; done'
1
2
3
4
5
$ ksh -c 'echo $KSH_VERSION'
Version JM 93u+ 2012-02-29

$ bash -c 'i=5; for x in {1..$i}; do echo "$x"; done'
{1..5}

#12


6  

This is another way:

这是另一种方式:

end=5
for i in $(bash -c "echo {1..${end}}"); do echo $i; done

#13


4  

These are all nice but seq is supposedly deprecated and most only work with numeric ranges.

这些都很好,但是seq被认为是不赞成的,而且大多数只适用于数值范围。

If you enclose your for loop in double quotes, the start and end variables will be dereferenced when you echo the string, and you can ship the string right back to BASH for execution. $i needs to be escaped with \'s so it is NOT evaluated before being sent to the subshell.

如果在双引号中包含for循环,那么当您返回字符串时,开始和结束变量将被取消,并且您可以将字符串返回到BASH执行。$i需要使用\'s进行转义,所以在发送给subshell之前不进行评估。

RANGE_START=a
RANGE_END=z
echo -e "for i in {$RANGE_START..$RANGE_END}; do echo \\${i}; done" | bash

This output can also be assigned to a variable:

这个输出也可以分配给一个变量:

VAR=`echo -e "for i in {$RANGE_START..$RANGE_END}; do echo \\${i}; done" | bash`

The only "overhead" this should generate should be the second instance of bash so it should be suitable for intensive operations.

这应该生成的唯一“开销”应该是bash的第二个实例,因此它应该适合于密集型操作。

#14


3  

Replace {} with (( )):

替换{}与(()):

tmpstart=0;
tmpend=4;

for (( i=$tmpstart; i<=$tmpend; i++ )) ; do 
echo $i ;
done

Yields:

收益率:

0
1
2
3
4

#15


2  

If you're doing shell commands and you (like I) have a fetish for pipelining, this one is good:

如果您正在执行shell命令,并且您(如我)对流水线操作有一种迷恋,那么这一项很好:

seq 1 $END | xargs -I {} echo {}

seq1 $END | xargs -I {}

#16


1  

If you want to stay as close as possible to the brace-expression syntax, try out the range function from bash-tricks' range.bash.

如果您想要尽可能地接近括号表达式的语法,请尝试从bash-技巧的range.bash中找到range函数。

For example, all of the following will do the exact same thing as echo {1..10}:

例如,下面的所有操作都将执行与echo{1. 10}相同的操作:

source range.bash
one=1
ten=10

range {$one..$ten}
range $one $ten
range {1..$ten}
range {1..10}

It tries to support the native bash syntax with as few "gotchas" as possible: not only are variables supported, but the often-undesirable behavior of invalid ranges being supplied as strings (e.g. for i in {1..a}; do echo $i; done) is prevented as well.

它试图以尽可能少的“gotchas”来支持本机bash语法:不仅支持变量,而且还提供了作为字符串提供的无效范围的经常不良行为(例如,在{1..a}中);echo $ i;也可以防止。

The other answers will work in most cases, but they all have at least one of the following drawbacks:

其他的答案在大多数情况下都适用,但它们都至少有以下缺点之一:

  • Many of them use subshells, which can harm performance and may not be possible on some systems.
  • 它们中的许多都使用子shell,这会损害性能,在某些系统上可能是不可能的。
  • Many of them rely on external programs. Even seq is a binary which must be installed to be used, must be loaded by bash, and must contain the program you expect, for it to work in this case. Ubiquitous or not, that's a lot more to rely on than just the Bash language itself.
  • 他们中的许多人依赖于外部项目。即使seq是必须安装的二进制文件,它必须由bash加载,并且必须包含您期望的程序,以便在这种情况下工作。无论是否普遍,这比Bash语言本身要多得多。
  • Solutions that do use only native Bash functionality, like @ephemient's, will not work on alphabetic ranges, like {a..z}; brace expansion will. The question was about ranges of numbers, though, so this is a quibble.
  • 只使用本机Bash功能的解决方案,如@ephemient的,将不会按字母的范围进行工作,比如{a..z};将支架扩张。问题是关于数字的范围,所以这是一个诡辩。
  • Most of them aren't visually similar to the {1..10} brace-expanded range syntax, so programs that use both may be a tiny bit harder to read.
  • 它们中的大多数在视觉上与{1.. ..10}扩展的范围语法,所以使用这两种方法的程序可能会有点难读。
  • @bobbogo's answer uses some of the familiar syntax, but does something unexpected if the $END variable is not a valid range "bookend" for the other side of the range. If END=a, for example, an error will not occur and the verbatim value {1..a} will be echoed. This is the default behavior of Bash, as well--it is just often unexpected.
  • @bobbogo的答案使用了一些熟悉的语法,但是如果$END变量不是在范围的另一端的有效范围“bookend”,则会发生一些意外的事情。如果END=a,则不会出现错误,而逐字的值{1..}将回荡。这也是Bash的默认行为——这常常是出乎意料的。

Disclaimer: I am the author of the linked code.

免责声明:我是链接代码的作者。

#17


0  

This works in Bash and Korn, also can go from higher to lower numbers. Probably not fastest or prettiest but works well enough. Handles negatives too.

在Bash和Korn中,也可以从更高到更低的数字。可能不是最快的,也不是最漂亮的,但是效果很好。处理消极。

function num_range {
   # Return a range of whole numbers from beginning value to ending value.
   # >>> num_range start end
   # start: Whole number to start with.
   # end: Whole number to end with.
   typeset s e v
   s=${1}
   e=${2}
   if (( ${e} >= ${s} )); then
      v=${s}
      while (( ${v} <= ${e} )); do
         echo ${v}
         ((v=v+1))
      done
   elif (( ${e} < ${s} )); then
      v=${s}
      while (( ${v} >= ${e} )); do
         echo ${v}
         ((v=v-1))
      done
   fi
}

function test_num_range {
   num_range 1 3 | egrep "1|2|3" | assert_lc 3
   num_range 1 3 | head -1 | assert_eq 1
   num_range -1 1 | head -1 | assert_eq "-1"
   num_range 3 1 | egrep "1|2|3" | assert_lc 3
   num_range 3 1 | head -1 | assert_eq 3
   num_range 1 -1 | tail -1 | assert_eq "-1"
}

#1


1106  

for i in $(seq 1 $END); do echo $i; done

edit: I prefer seq over the other methods because I can actually remember it ;)

编辑:我更喜欢seq,而不是其他方法,因为我实际上可以记住它;

#2


288  

The seq method is the simplest, but Bash has built-in arithmetic evaluation.

seq方法是最简单的,但是Bash有内置的算术计算。

END=5
for ((i=1;i<=END;i++)); do
    echo $i
done
# ==> outputs 1 2 3 4 5 on separate lines

The for ((expr1;expr2;expr3)); construct works just like for (expr1;expr2;expr3) in C and similar languages, and like other ((expr)) cases, Bash treats them as arithmetic.

为((expr1;expr2;expr3));在C语言和类似的语言中,构建工作就像(expr1;expr2;expr3),和其他(expr)的例子一样,Bash将它们视为算术。

#3


156  

discussion

Using seq is fine, as Jiaaro suggested. Pax Diablo suggested a Bash loop to avoid calling a subprocess, with the additional advantage of being more memory friendly if $END is too large. Zathrus spotted a typical bug in the loop implementation, and also hinted that since i is a text variable, continuous conversions to-and-fro numbers are performed with an associated slow-down.

正如Jiaaro所建议的,使用seq是可以的。Pax Diablo建议使用Bash循环来避免调用子进程,如果$END太大,则具有更多内存友好的额外优势。Zathrus在循环实现中发现了一个典型的bug,并且还暗示由于我是一个文本变量,所以连续的转换数字是通过一个相关的减速来执行的。

integer arithmetic

This is an improved version of the Bash loop:

这是Bash循环的改进版本:

typeset -i i END
let END=5 i=1
while ((i<=END)); do
    echo $i
    …
    let i++
done

If the only thing that we want is the echo, then we could write echo $((i++)).

如果我们想要的只是echo,那么我们可以写echo $((i++))。

ephemient taught me something: Bash allows for ((expr;expr;expr)) constructs. Since I've never read the whole man page for Bash (like I've done with the Korn shell (ksh) man page, and that was a long time ago), I missed that.

ephemient教会了我一些东西:Bash允许((expr;expr;expr))构造。因为我从来没有读过Bash的整个手册页(就像我用Korn shell (ksh)手册所做的那样,那是很久以前的事了),我错过了。

So,

所以,

typeset -i i END # Let's be explicit
for ((i=1;i<=END;++i)); do echo $i; done

seems to be the most memory-efficient way (it won't be necessary to allocate memory to consume seq's output, which could be a problem if END is very large), although probably not the “fastest”.

似乎是最有效的方法(不需要分配内存来消耗seq的输出,这可能是一个问题,如果结束非常大),尽管可能不是“最快的”。

the initial question

eschercycle noted that the {a..b} Bash notation works only with literals; true, accordingly to the Bash manual. One can overcome this obstacle with a single (internal) fork() without an exec() (as is the case with calling seq, which being another image requires a fork+exec):

eschercycle注意到{a.. ..b} Bash符号只适用于文字;确实,根据Bash手册。一个人可以用一个(内部)fork()来克服这个障碍,而没有exec()(就像调用seq的情况一样,这是另一个图像需要一个fork+exec):

for i in $(eval echo "{1..$END}"); do

Both eval and echo are Bash builtins, but a fork() is required for the command substitution (the $(…) construct).

eval和echo都是Bash builtins,但是命令替换需要一个fork()($(…)构造)。

#4


81  

Here is why the original expression didn't work.

这就是为什么最初的表达不起作用。

From man bash:

从人抨击:

Brace expansion is performed before any other expansions, and any characters special to other expansions are preserved in the result. It is strictly textual. Bash does not apply any syntactic interpretation to the context of the expansion or the text between the braces.

在任何其他扩展之前执行括号扩展,在结果中保留其他扩展的特殊字符。它是严格的文本。Bash不将任何语法解释应用到扩展的上下文或括号之间的文本。

So, brace expansion is something done early as a purely textual macro operation, before parameter expansion.

因此,在参数展开之前,先做一个纯文本的宏操作,这样做是很早就完成的。

Shells are highly optimized hybrids between macro processors and more formal programming languages. In order to optimize the typical use cases, the language is made rather more complex and some limitations are accepted.

shell是在宏处理器和更正式的编程语言之间高度优化的混合。为了优化典型的用例,语言变得更加复杂,一些限制被接受。

Recommendation

建议

I would suggest sticking with Posix1 features. This means using for i in <list>; do, if the list is already known, otherwise, use while or seq, as in:

我建议你坚持使用Posix1特性。这意味着在 中使用i;如果列表已知,则使用while或seq,如:

#!/bin/sh

limit=4

i=1; while [ $i -le $limit ]; do
  echo $i
  i=$(($i + 1))
done
# Or -----------------------
for i in $(seq 1 $limit); do
  echo $i
done


1. Bash is a great shell and I use it interactively, but I don't put bash-isms into my scripts. Scripts might need a faster shell, a more secure one, a more embedded-style one. They might need to run on whatever is installed as /bin/sh, and then there are all the usual pro-standards arguments. Remember shellshock, aka bashdoor?

#5


41  

The POSIX way

POSIX的方式

If you care about portability, use the example from the POSIX standard:

如果您关心可移植性,请使用POSIX标准中的示例:

i=2
end=5
while [ $i -le $end ]; do
    echo $i
    i=$(($i+1))
done

Output:

输出:

2
3
4
5

Things which are not POSIX:

不是POSIX的东西:

  • (( )) without dollar, although it is a common extension as mentioned by POSIX itself.
  • 没有美元,尽管它是POSIX本身所提到的公共扩展。
  • [[. [ is enough here. See also: What is the difference between single and double square brackets in Bash?
  • [[。(这里就足够了。参见:Bash中单个和双方括号的区别是什么?
  • for ((;;))
  • ((,))
  • seq (GNU Coreutils)
  • seq(GNU Coreutils)
  • {start..end}, and that cannot work with variables as mentioned by the Bash manual.
  • {开始. .end},并且不能使用Bash手册所提到的变量。
  • let i=i+1: POSIX 7 2. Shell Command Language does not contain the word let, and it fails on bash --posix 4.3.42
  • 让i=i+1: POSIX 7 2。Shell命令语言不包含let,并且在bash中失败——posix 4.3.42。
  • the dollar at i=$i+1 might be required, but I'm not sure. POSIX 7 2.6.4 Arithmetic Expansion says:

    i=$i+1的美元可能是需要的,但我不确定。POSIX 7 2.6.4算法扩展说:

    If the shell variable x contains a value that forms a valid integer constant, optionally including a leading plus or minus sign, then the arithmetic expansions "$((x))" and "$(($x))" shall return the same value.

    如果shell变量x包含一个值,该值形成一个有效的整数常量,可选地包括一个前置加号或减号,那么算术展开式“$(x)”和“$($x)”将返回相同的值。

    but reading it literally that does not imply that $((x+1)) expands since x+1 is not a variable.

    但是从字面上看,这并不意味着$((x+1))的扩展,因为x+1不是一个变量。

#6


28  

Another layer of indirection:

另一个间接层:

for i in $(eval echo {1..$END}); do
    ∶

#7


18  

If you're on BSD / OS X you can use jot instead of seq:

如果你在BSD / OS X上,你可以用jot代替seq:

for i in $(jot $END); do echo $i; done

#8


17  

You can use

您可以使用

for i in $(seq $END); do echo $i; done

#9


12  

This works fine in bash:

这在bash中很有效:

END=5
i=1 ; while [[ $i -le $END ]] ; do
    echo $i
    ((i = i + 1))
done

#10


8  

If you need it prefix than you might like this

如果你需要它的前缀,你可能会喜欢它。

 for ((i=7;i<=12;i++)); do echo `printf "%2.0d\n" $i |sed "s/ /0/"`;done

that will yield

这将产生

07
08
09
10
11
12

#11


6  

I know this question is about bash, but - just for the record - ksh93 is smarter and implements it as expected:

我知道这个问题是关于bash的,但是-仅仅为了记录- ksh93是更聪明的,并按照预期实现它:

$ ksh -c 'i=5; for x in {1..$i}; do echo "$x"; done'
1
2
3
4
5
$ ksh -c 'echo $KSH_VERSION'
Version JM 93u+ 2012-02-29

$ bash -c 'i=5; for x in {1..$i}; do echo "$x"; done'
{1..5}

#12


6  

This is another way:

这是另一种方式:

end=5
for i in $(bash -c "echo {1..${end}}"); do echo $i; done

#13


4  

These are all nice but seq is supposedly deprecated and most only work with numeric ranges.

这些都很好,但是seq被认为是不赞成的,而且大多数只适用于数值范围。

If you enclose your for loop in double quotes, the start and end variables will be dereferenced when you echo the string, and you can ship the string right back to BASH for execution. $i needs to be escaped with \'s so it is NOT evaluated before being sent to the subshell.

如果在双引号中包含for循环,那么当您返回字符串时,开始和结束变量将被取消,并且您可以将字符串返回到BASH执行。$i需要使用\'s进行转义,所以在发送给subshell之前不进行评估。

RANGE_START=a
RANGE_END=z
echo -e "for i in {$RANGE_START..$RANGE_END}; do echo \\${i}; done" | bash

This output can also be assigned to a variable:

这个输出也可以分配给一个变量:

VAR=`echo -e "for i in {$RANGE_START..$RANGE_END}; do echo \\${i}; done" | bash`

The only "overhead" this should generate should be the second instance of bash so it should be suitable for intensive operations.

这应该生成的唯一“开销”应该是bash的第二个实例,因此它应该适合于密集型操作。

#14


3  

Replace {} with (( )):

替换{}与(()):

tmpstart=0;
tmpend=4;

for (( i=$tmpstart; i<=$tmpend; i++ )) ; do 
echo $i ;
done

Yields:

收益率:

0
1
2
3
4

#15


2  

If you're doing shell commands and you (like I) have a fetish for pipelining, this one is good:

如果您正在执行shell命令,并且您(如我)对流水线操作有一种迷恋,那么这一项很好:

seq 1 $END | xargs -I {} echo {}

seq1 $END | xargs -I {}

#16


1  

If you want to stay as close as possible to the brace-expression syntax, try out the range function from bash-tricks' range.bash.

如果您想要尽可能地接近括号表达式的语法,请尝试从bash-技巧的range.bash中找到range函数。

For example, all of the following will do the exact same thing as echo {1..10}:

例如,下面的所有操作都将执行与echo{1. 10}相同的操作:

source range.bash
one=1
ten=10

range {$one..$ten}
range $one $ten
range {1..$ten}
range {1..10}

It tries to support the native bash syntax with as few "gotchas" as possible: not only are variables supported, but the often-undesirable behavior of invalid ranges being supplied as strings (e.g. for i in {1..a}; do echo $i; done) is prevented as well.

它试图以尽可能少的“gotchas”来支持本机bash语法:不仅支持变量,而且还提供了作为字符串提供的无效范围的经常不良行为(例如,在{1..a}中);echo $ i;也可以防止。

The other answers will work in most cases, but they all have at least one of the following drawbacks:

其他的答案在大多数情况下都适用,但它们都至少有以下缺点之一:

  • Many of them use subshells, which can harm performance and may not be possible on some systems.
  • 它们中的许多都使用子shell,这会损害性能,在某些系统上可能是不可能的。
  • Many of them rely on external programs. Even seq is a binary which must be installed to be used, must be loaded by bash, and must contain the program you expect, for it to work in this case. Ubiquitous or not, that's a lot more to rely on than just the Bash language itself.
  • 他们中的许多人依赖于外部项目。即使seq是必须安装的二进制文件,它必须由bash加载,并且必须包含您期望的程序,以便在这种情况下工作。无论是否普遍,这比Bash语言本身要多得多。
  • Solutions that do use only native Bash functionality, like @ephemient's, will not work on alphabetic ranges, like {a..z}; brace expansion will. The question was about ranges of numbers, though, so this is a quibble.
  • 只使用本机Bash功能的解决方案,如@ephemient的,将不会按字母的范围进行工作,比如{a..z};将支架扩张。问题是关于数字的范围,所以这是一个诡辩。
  • Most of them aren't visually similar to the {1..10} brace-expanded range syntax, so programs that use both may be a tiny bit harder to read.
  • 它们中的大多数在视觉上与{1.. ..10}扩展的范围语法,所以使用这两种方法的程序可能会有点难读。
  • @bobbogo's answer uses some of the familiar syntax, but does something unexpected if the $END variable is not a valid range "bookend" for the other side of the range. If END=a, for example, an error will not occur and the verbatim value {1..a} will be echoed. This is the default behavior of Bash, as well--it is just often unexpected.
  • @bobbogo的答案使用了一些熟悉的语法,但是如果$END变量不是在范围的另一端的有效范围“bookend”,则会发生一些意外的事情。如果END=a,则不会出现错误,而逐字的值{1..}将回荡。这也是Bash的默认行为——这常常是出乎意料的。

Disclaimer: I am the author of the linked code.

免责声明:我是链接代码的作者。

#17


0  

This works in Bash and Korn, also can go from higher to lower numbers. Probably not fastest or prettiest but works well enough. Handles negatives too.

在Bash和Korn中,也可以从更高到更低的数字。可能不是最快的,也不是最漂亮的,但是效果很好。处理消极。

function num_range {
   # Return a range of whole numbers from beginning value to ending value.
   # >>> num_range start end
   # start: Whole number to start with.
   # end: Whole number to end with.
   typeset s e v
   s=${1}
   e=${2}
   if (( ${e} >= ${s} )); then
      v=${s}
      while (( ${v} <= ${e} )); do
         echo ${v}
         ((v=v+1))
      done
   elif (( ${e} < ${s} )); then
      v=${s}
      while (( ${v} >= ${e} )); do
         echo ${v}
         ((v=v-1))
      done
   fi
}

function test_num_range {
   num_range 1 3 | egrep "1|2|3" | assert_lc 3
   num_range 1 3 | head -1 | assert_eq 1
   num_range -1 1 | head -1 | assert_eq "-1"
   num_range 3 1 | egrep "1|2|3" | assert_lc 3
   num_range 3 1 | head -1 | assert_eq 3
   num_range 1 -1 | tail -1 | assert_eq "-1"
}