你们中的一些人可能对Project Euler很熟悉,而且我现在正在尝试他们的一些问题来教给自己更多的bash。他们比's-script&y;'但它有助于语法等。
问题目前要求我解决:
如果我们列出10以下的所有自然数是3或5的倍数,我们得到3,5,6和9.这些倍数的总和是23.
查找低于1000的3或5的所有倍数的总和。
我的代码如下:
#!/bin/bash
i="1"
for i in `seq 1 333`
do
threes[$i]=`calc $i*3` # where 'calc' is a function written in bashrc
#calc actually looks like: calc() {awk "BEGIN { print "$*"} }
let "sumthrees = sumthrees + ${threes[$i]}"
done
for i in `seq 1 199`
do
fives[$i]=`calc $i*5`
let "sumfives = sumfives + ${fives[$i]}"
done
let "ans = $sumfives + $sumthrees"
echo "The sum of all 3 factors is $sumthrees and the sum of all five factors is $sumfives"
echo "The sum of both is $ans"
#So I can repeatedly run the script without bash remembering the variables between executions
unset i
unset fives
unset threes
unset sumfives
unset sumthrees
unset ans
到目前为止,我还没有得到正确答案,但对于我出错的地方已经没有了。 (仅供参考,剧本目前给我266333,我相信这很接近,但我还不知道答案。)
任何人都能看到任何东西吗?而对于我自己的学习,如果有更优雅的解决方案,人们可能愿意分享这将是伟大的。
修改
感谢所有的答案,超级翔实。由于这里有很多有用的答案,我接受我最喜欢的答案作为正确的答案。
答案 0 :(得分:3)
蓝月亮指出了你逻辑的实际问题。
您不需要将所有三和五个存储在数组中,因为您以后不需要它们。
如果您使用./yourscript
或bash script
,则无需在脚本末尾取消设置变量,因为它们会随着
shell实例(最好在任何情况下首先初始化它们。)
您不需要awk
来做数学,bash
就可以了。
seq
和let
不是在bash脚本中执行任何操作的最佳方式。
这是一个直截了当的版本:
#!/bin/bash
sum=0
for ((i=1; i<1000; i++))
do
if (( i%3 == 0 || i%5 == 0 ))
then
(( sum += i ))
fi
done
echo "$sum"
答案 1 :(得分:2)
你的逻辑几乎是正确的,除了有数字除以 3 和 5.所以你要将这些数字加两次。因此,你的回答是错误的。
使用另一个类似于你的循环,并从结果中减去除以3和5的循环。
答案 2 :(得分:2)
您可能会发现一些有用的提示:
在bash中,您使用let
为shell提供一个变量应该被视为数字的提示。所有bash变量都是字符串,但您可以对数字字符串进行算术运算。如果我说let i=1
,那么我将设置为1,但如果我说let i="taco"
,那么$i
将为0,因为它无法读取为数字。在shell中进行数学工作时,您可以实现少量的类型安全性。
Bash还有$((this))
数学机制!您可以自行查看:echo $((2 + 2))
- &gt; 4
,与此问题更相关:echo $((6 % 3 == 0))
- &gt; 1
如果您不熟悉,%
将第一个数字除以第二个数字,并返回余数;当余数为0时,意味着第一个是可分割的第二个! ==
是测试两个事物是否相等的测试,对于像这样的逻辑测试,1代表true,0代表false。所以我正在测试6是否可以被3整除,它是,并且我得到的值是1。
测试括号[ ... ]
有一个“test for equality”标志-eq
,您可以使用它来检查数学表达式是否具有某个值(man test for more details)!< / p>
$ let i=6
$ echo $((i % 3 == 0 || i % 5 == 0))
1
$ if [ $((i % 3 == 0 || i % 5 == 0)) -eq 1 ]; then echo "yes"; fi
yes
(||
是另一个逻辑测试 - 当a为真或 b为真时,$((a || b))
将为1(真)。
最后,不是为数字6执行此操作,而是可以在for循环中执行此操作,并在每次找到3或5的倍数时递增sum变量:
let sum=0
for i in {1..1000}; do
if [ $((i % 3 == 0 || i % 5 == 0)) -eq 1 ]; then
let sum=$((sum + i))
fi
done
echo $sum
你有一个可行的解决方案!
Bash有很多不错的小技巧(而且更多的意思是丑陋的技巧),但至少要学习它们中的一小部分才能将它作为脚本工具使用。答案 3 :(得分:2)
如何创造性地使用模数函数&amp;一些检查。然后你只有一个循环。
#!/bin/bash
i=1
while [ $i -lt 1000 ]
do
if [ $(($i % 3)) -eq 0 ] || [ $(($i % 5)) -eq 0 ]
then
sumall=$(($sumall+$i))
fi
i=$(($i+1))
done
echo "The sum of both is $sumall"
答案:233168
答案 4 :(得分:1)
另一种解决方案:
#!/bin/bash
sum=0
for n in {1..999}; do [ $(((n%5) * (n%3))) -eq 0 ] && sum=$((sum+n)); done
echo $sum
脚本循环遍历1000以下的所有数字,测试数字mod 3和数字mod 5的乘积是否为0(如果其中一个数字为零,则两个数字的乘积只能为零)。如果是这种情况,它会将当前数字添加到一个总和中,然后打印出来。
顺便说一下,如果我是你,我会在脚本中包含calc
函数的定义,以获得一个不需要你特定配置的独立解决方案。