如何在Bash中使用取模运算符?

227

我正在尝试这样一行代码:

for i in {1..600}; do wget http://example.com/search/link $i % 5; done;

我想要得到的输出是:

wget http://example.com/search/link0
wget http://example.com/search/link1
wget http://example.com/search/link2
wget http://example.com/search/link3
wget http://example.com/search/link4
wget http://example.com/search/link0

但实际上我得到的只是:

    wget http://example.com/search/link
6个回答

316
尝试以下操作:
 for i in {1..600}; do echo wget http://example.com/search/link$(($i % 5)); done

$(( ))语法对内容进行算术计算


13
如果有人需要在bash中进行数学运算,请注意,使用负数的取模运算仅返回余数,而不是数学上的取模结果。这意味着,虽然在数学上-12 mod 108,但在bash中会计算为-2。你可以用简单的echo $((-12 % 10))-2)来测试它,并将其与python3 -c "print(-12 % 10)"8)进行比较。 - Lirt
15
不要忘记算术结构 $(()) 会自动展开变量,所以你不需要在 i 前加 $。这样 $((i % 5)) 就能完美地工作了。 - Yokai

56
for i in {1..600}
do
    n=$(($i%5))
    wget http://example.com/search/link$n
done

3
双括号内的美元符号是不必要的,因为Bash会自动展开其中的变量。 - Sxilderik

33

你必须将数学表达式放在 $(( )) 内。

一行代码:

for i in {1..600}; do wget http://example.com/search/link$(($i % 5)); done;

多行:

for i in {1..600}; do
    wget http://example.com/search/link$(($i % 5))
done

3
双括号中的$符号是不必要的,因为Bash会自动展开其中的任何变量。 - Sxilderik

14

这可能与主题无关。但是对于for循环中的wget,您肯定可以这样做:

curl -O http://example.com/search/link[1-600]

3

在bash中使用所有bash运算符(+,-,/,*,**,&,&&,<<等)和算术扩展

到目前为止,有346k名访问者来到这个问题,我敢打赌其中344.9k人只是想要这个问题的标题的答案:

如何在bash中使用取模运算符?

即使我谷歌搜索"bash modulus"寻找那个答案,最后还是来到了这里。所以,既然我已经弄清楚了,我们就直接跳到正题:

如何在bash中使用取模(%)运算符

只需像这样做:

# 7 mod 4 (answer is 3, but to print the output you must use one of the cmds
# below)
$((7 % 4))

# [PREFERRED: no quotes]
# print the result (double quotes are not required)
echo $((7 % 4))

# print the result (with double quotes if you like)
echo "$((7 % 4))"

带变量的示例:

num1="7"
num2="4"

# [PREFERRED: no $ signs nor extraneous quotes] result is 3
echo $((num1 % num2))

# Also ok: with $ signs
echo $(($num1 % $num2))

# Also ok: with $ signs and extra quotes
echo "$(("$num1" % "$num2"))"

将结果存储到一个变量中:
mod=$((num1 % num2))
echo "$mod"  # result is 3

这些概念的主要学习链接是来自GNU bash官方用户手册
  1. Bash算术扩展
  2. Bash Shell算术

更多关于bash的"算术扩展"

我从@Mark Longair的回答中学到了上述内容(尽管我花了一些功夫才理解全部内容),那就是我得到下面链接的地方。然后我进行了更多的研究。

$(( )) 部分被称为 "算术扩展",并在官方GNU bash 用户手册中进行了描述,链接在这里:https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Arithmetic-Expansion

基本示例(在每个示例前面加上echo以查看结果打印到屏幕上):

# general form
$((mathematical_expression))

# addition
$((7 + 4))  # 11

# subtraction
$((7 - 4))  # 3

# modulus (remainder)
$((7 % 4))  # 3

# logical AND
$((7 && 4))  # 1

# bitwise AND
$((7 & 4))  # 4

# etc.
# See the full operator list below for more

算术扩展周围不需要双引号。根据上述手册(强调添加):

表达式被视为在双引号内,但括号内的双引号不会被特殊处理。表达式中的所有标记都会经历参数和变量扩展、命令替换和引号去除。结果被视为要评估的算术表达式。算术扩展可以嵌套。

有关所有 shell 算术运算符,请参阅 GNU bash 手册中的"Shell Arithmetic"部分,链接在这里:https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Arithmetic

您基本上可以使用 C 语言的所有数学运算符。算术运算是“在没有溢出检查的固定宽度整数中进行的”,因此如果您执行 echo $((11/10))echo $((19/10)),两种情况下都会得到 1,因为对于整数来说,小数部分被截断。

根据刚才提供的手册链接(强调添加):

评估使用固定宽度整数进行,没有检查溢出,但除以0会被捕获并标记为错误。操作符及其优先级、结合性和值与C语言相同。
由于bash中的算术运算符与C语言具有相同的优先级,如上所述,您还可以参考cppreference社区维基上的C运算符优先级:https://en.cppreference.com/w/c/language/operator_precedence <-- 把它放进你的工具包里。
Shell算术:这里是GNU Bash手册中支持的所有操作符
它们按照从高到低的优先级列出。
  1. id++ id--
    1. 变量后增和后减
  2. ++id --id
    1. 变量前增和前减
  3. - +
    1. 一元减和加
  4. ! ~
    1. 逻辑和按位取反
  5. **
    1. 乘方
  6. * / %
    1. 乘法、除法、取余
  7. + -
    1. 加法、减法
  8. << >>
    1. 左移和右移
  9. <= >= < >
    1. 比较
  10. == !=
    1. 相等和不相等
  11. &
    1. 按位与
  12. ^
    1. 按位异或
  13. |
    1. 按位或
  14. &&
    1. 逻辑与
  15. ||
    1. 逻辑或
  16. expr ? expr : expr
    1. 条件运算符
  17. = *= /= %= += -= <<= >>= &= ^= |=
    1. 赋值
  18. expr1 , expr2
    1. 逗号

在算术中使用不同的进制,例如二进制(基数为2)、八进制(基数为8)和十六进制(基数为16)

要了解如何使用不同的进制(如二进制(基数为2)、八进制(基数为8)或十六进制(基数为16))与bash算术运算符一起使用,请阅读下面几段文字手册中上面的“Shell Arithmetic”列表

以下是一些快速示例,其中包含用于数学计算的十进制(基数为10)、八进制(基数为8)、十六进制(基数为16)和二进制(基数为2)的输入数字:

# hex 0xa (decimal 10) + decimal 5 = decimal 15
echo $((0xa + 5))  # prints `15` (decimal 15)
# OR (same thing)
echo $((16#a + 5))  # prints `15` (decimal 15)

# octal 071 (decimal 57) + hex 0xaa (decimal 170) = decimal 227
echo $((071 + 0xaa))  # prints `227` (decimal 227)
# OR (same thing)
echo $((8#71 + 16#aa))  # prints `227` (decimal 227)

# binary 1011 (decimal 11) + decimal 2 = decimal 13
echo $((2#1011 + 2))  # prints `13` (decimal 13)

# binary 1111 (decimal 15) + binary 11111 (decimal 31) = decimal 46
echo $((2#1111 + 2#11111))  # prints `46` (decimal 46)

要以十六进制打印,请使用printf "0x%X\n" 数字

# prints `0x2E` (hex 2E, or decimal 46)
printf "0x%X\n" $((2#1111 + 2#11111))

要以二进制形式打印,请使用bc(参见这里的我的答案):
# prints `0b101110` (decimal 46)
printf "0b%s\n" "$(echo "obase=2; $((2#1111 + 2#11111))" | bc)"

另请参阅

  1. [我的回答] 如何在bash中使用浮点运算?
  2. 如果你需要一个完整的bash浮点库,可以轻松导入(源代码),请使用我在这里的代码:bash/floating_point_math.sh 在我的eRCaGuy_hello_world存储库中。
    1. 还可以参考我关于在Bash中使用库的回答:详细示例:如何编写、导入、使用和测试Bash库?

0
这篇文章有点老了,但我觉得还是需要做出一些贡献,因为我在尝试通过自动化来设置键盘颜色的过程中偶然发现了这个问题。
我创建了一个简单的BASH脚本,我每分钟从我的ROOT chrontab中调用它,以便随着时间的推移设置键盘的颜色。你可以根据自己的需求调整颜色模式和取模运算。这只是一个很好的起点。
#!/bin/bash
# must run as ROOT to work
# put in your root crontab to change the color at set times

sec=$(date +%s)
min=$(( $sec / 60 ))
col=$(( $min % 7 ))
colors=('0000FF' '00FF00' '00FFFF' 'FF0000' 'FF00FF' 'FFFF00' 'FFFFFF')
colorFile="/sys/class/leds/system76_acpi::kbd_backlight/color"

if [ -f "$colorFile" ]; then
    echo "Set keyboard to color $col ~ ${colors[$col]}"
    echo "${colors[$col]}" > "$colorFile"
fi

希望你喜欢它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接