我怎样才能使脚本数到五?


10

我试图制作一个非常简单的bash脚本,以列出375和3500之间的所有5的倍数(375、380、385 ...)。我尝试但没有起作用的一件事是:

for i in {375..3500}
do
        echo $i
        (($i += 5))
done

一段时间后,我放弃了,并在15秒钟内用BASIC编写了此代码:

10 count = 375
20 print count
30 count = count+5
40 if count < 3500 then goto 20

如何在bash脚本中制作BASIC程序?


这在堆栈溢出时更好-Unix和Linux是关于操作系统而不是编码的。编码用于堆栈溢出。
noɥʇʎԀʎzɐɹƆ

Answers:


20

或者,可以使用传统的C风格的for循环:

for ((i=375; i<=3500; i+=5)); do
    echo $i
done

这也许不如使用seq清楚,但它不会产生任何子进程。尽管由于我熟悉C,所以我对此毫无困难,但是YMMV。


1
这种方法的缺点是它的可移植性较差。seq方法在POSIX sh中有效。
Wouter Verhelst 2015年

哦,POSIX sh中不存在C样式的for循环吗?您每天都在学习新东西……
Muzer 2015年

2
@WouterVerhelst好吧,除非您仅限于POSIX sh,否则您不太可能拥有seq,它是GNU coreutils的一部分。busybox的实现较为有限,但除此之外,许多嵌入式系统可能根本没有。
克里斯·

1
@Muzer-至少dash不支持它。@ChrisDown-没有理由说“ POSIX sh” 必须暗示“ no seq”。但是,是的,我确实忽略了POSIX未指定seq的事实。
Wouter Verhelst

27

由于仍然使用括号扩展,因此请充分利用其功能:

echo {375..3500..5}

您还可以使用printf代替来使用此技术在每个行中以可选文本打印每个数字echo,例如:

$ printf "Number %s is generated.\n" {375..3500..5}
Number 375 is generated.
Number 380 is generated.
Number 385 is generated.
...

编辑

正如@kojiro在评论中指出的,Mac OS使用bash 3作为默认外壳程序,它不支持在花括号扩展的序列表达式中增加。您需要升级到bash版本4或使用其他支持该版本的shell(例如,最新的zsh)。


2
在Mac OS 10.10.3上,这对我不起作用。它输出'{375..3500..5}'。
aswine 2015年

6
这就是为什么@aswine 在询问时总是要提及您的操作系统的原因。特别是由于OSX与其他UNICE和Linux都有许多差异。
terdon

2
这本身并不是操作系统的区别。这是版本差异。OS X仅具有BASH 3 OOTB。您几乎可以使用任何OS X软件包管理器来安装本世纪的BASH。我使用Home Brew,其中之一。
kojiro

2
扩展失败的事实直接运行,但成功的事实在bash -c很大程度上保证了涉及两个不同的shell。会$SHELL --version说是bash 3吗?
dhag 2015年

3
@mikeserv答案很简单-我之所以没有写出来,是因为我不知道bash引入该功能的哪个版本。我自己是从小次郎的评论中学到的。而且,请不要将我与SC进行比较,我真的不知道自1970年末以来所有炮弹的所有详细信息和历史。再次-如果您期望如此,请拒绝投票。
jimmij 2015年

17

使用SEQ(1)

for i in $(seq 375 5 3500)
do
    echo $i
done

或者,简单地:

seq 375 5 3500

4
更简单的方法是删除循环并使用seq 375 5 3500
dhag 2015年

11

您的for循环摘要无法按您的要求运行,原因有两个:

  • (($i += 5))-在此将$i扩展为的值i。因此,扩展将类似于((375 += 5)),这是没有意义的(试图将一个文字数字分配给另一个文字数字)。通常,这可以通过((i += 5))(不$扩展变量)来实现
  • {375..3500}会循环的第一次迭代前都会进行扩展。这将是数字列表375 376 ... 3499 3500。对于循环的每次迭代,i将一对一地分配给每个数字。因此,在每次迭代开始时,i将被重新分配给该列表中的下一个值,以1为步长进行计数。((i += 5))实际上什么也没做-它确实将i加了5,但随后只是在i的开始处再次重新分配了i。下一次迭代。

我认为我for (( ; ; ))最喜欢这个答案,但是这里有一些替代方法可以让您思考:


由于我们正在处理5的倍数,并且{a..b..i}bash版本3.2.57(1)(在OS X中不支持该扩展),因此我们可以执行以下操作:

for i in 375 {38..349}{0,5} 3500; do
    echo $i
done

这演示了如何使用bash来创建笛卡尔积。


我认为一般来说,for循环是执行此操作最方便的方法,但是如果您有兴趣,可以使用while循环(与BASIC更加接近):

count=375
while (( count <= 3500 )); do
    echo $count
    (( count += 5 ))
done

1
@jimmij ...什么是笛卡尔积?您可以根据需要拒绝评论,如果您告诉我,我什至都不在乎。我很好奇。
mikeserv

1
@mikeserv,您不能拒绝对此评论:en.wikipedia.org/wiki/Cartesian_product
jimmij

@jimmij-如果可以,我还是可以的。
mikeserv

@jimmij你在说恶魔吗?笛卡尔乘积是来自两个集合(可能是也可能不是同一集合)中的元素的每种可能组合的元组集合。通俗地说,这只是两组事物的“所有可能组合”。我只看到一套。这里的笛卡尔积如何?
jpmc26

1
@ jpmc26是的,它是“所有可能的组合”,所以让我们绘制两个轴-首先写38直到的所有数字349。第二秒只有两个数字:05。现在,让我们创建有序对那些所有组合的-你可以把它们写为集:{38,0}{38,5}... {349,5},或者只是删除冗余的符号{,}和获得...新号码380...... 3495
jimmij

5

当然,虽然有一个用于该(seq 375 5 3500)的应用程序,但是有多种方法可以从命令行执行此操作。虽然最快,最简单的方法就是使用seq,但是还有其他一些选择:

for i in {375..3500}; do [[ (($i % 5)) -eq 0 ]] && echo $i; done

i=370; while [ $i -le 3500 ]; do printf "%s\n" $((i+=5)); done

perl -le '$i=shift;while($i<=$ARGV[0]){print $i; $i+=5; }' 375 3500
perl -le 'map{print $_ + 5} 370..3495'

awk 'BEGIN{ for(i=375;i<=3500;i+=5){print i}}'

尼特·皮克:$(($i % 5))可以写$((i % 5))
G-Man说'恢复莫妮卡'

4

POSIXly:

i=370
while [ 3500 -gt "$i" ]
do    echo "$((i+=5))"
done

...要么...

echo 'for(x=370;x<=3500;x+=5)x' |bc

我不知道为什么你会用其他方式。当然,除了...

seq 375 5 3500

...或使用dc

echo '370[5+pd3500>p]splpx'|dc

我对dc代码的工作方式很好奇。当然,比使用更具吸引力seq
dhag 2015年

1
@dhag-它编写了一个小循环。它s鸟纲的[]到顶部p阵列,然后l的OAD回入堆栈和e的顶部xecutes它作为宏。在宏我们推5到堆栈然后弹出并从顶部的第二个和+他们,与他们的总和,这是更换两个堆栈值printed和duplicated之前3500被压入堆栈,当我们弹出它,我们只是做了欺骗比较>。如果3500更大,我们将存储在p数组中的字符串(我们当前的宏)作为宏加载并执行,否则不中断。
mikeserv

3

如果您坚持使用Bash 3:

echo {375..3500} | tr ' ' '\n' | sed -n 'p;n;n;n;n'

并且如果您喜欢awk

echo {375..3500} | tr ' ' '\n' | awk '!((NR-1)%5)'

我不知道括号的扩展-这真的很酷。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.