newprime.sh: 第 14 行: [: 0+1: 预期的整数表达式

newprime.sh: line 14: [: 0+1: integer expression expected

我的代码有什么问题?我正在尝试打印最多 n 位的素数

 echo Enter Number
    read num
    for (( i=2; $i <= $num ; i++ ))
    do
            c=0
            for (( j=2; $j <= $i ; j++))
            do
                    mod=$(($i % $j))
                    if  [ "$mod" -eq 0 ]
                    then
                            c=`expr $c+1`
                    fi
            done
            if [ "$c" -eq 1 ]
            then
                    echo $c
    
            fi
    done

我不知道我做错了什么。如果有人能告诉我如何修复它,我将不胜感激

newprime.sh: line 14: [: 0+1: integer expression expected
newprime.sh: line 14: [: 0+1: integer expression expected
newprime.sh: line 14: [: 0+1+1: integer expression expected
newprime.sh: line 14: [: 0+1: integer expression expected
newprime.sh: line 14: [: 0+1+1+1: integer expression expected
newprime.sh: line 14: [: 0+1: integer expression expected

expr 要求将参数作为单独的参数传递。引用 the POSIX standard for expr:

The application shall ensure that each of the expression operator symbols [...] and the symbols integer and string in the table are provided as separate arguments to expr.

此处的代码将所有运算符附加到一个参数中,因此出现了问题。


因此:

c=$(expr "$c" + 1)

...不...

c=$(expr $c+1)

但是千万不要那样做。这样写更高效,更易读:

c=$(( c + 1 ))

用更少的迭代优化POSIX shell 版本:

#!/usr/bin/env sh

printf %s 'Enter Number: '
read -r num
i=1
while [ "$i" -le "$num" ]; do
  c=0
  j=2
  # Stop checking division when divisor power 2 is greater than number
  # or we identifed a divisor
  while [ "$((j * j))" -le "$i" ] && [ "$c" -eq 0 ]; do
    c=$((i % j == 0))
    j=$((j + 1))
  done
  if [ "$c" -eq 0 ]; then
    printf '%s\n' "$i"
  fi
  i=$((i + 2))
done

或使用函数:

#!/usr/bin/env sh

is_prime() {
  j=2
  # Check j is a divisor of argument number, while j^2 is less than number
  while [ "$((j * j))" -le "" ]; do
    # If j is a divisor of number before the end of the loop
    # number is not prime, so return 1
    [ "$(( % j))" -eq 0 ] && return 1
    j=$((j + 1))
  done
}

printf %s 'Enter Number: '
read -r num
i=1
while [ "$i" -le "$num" ]; do
  if is_prime "$i"; then
    printf '%s\n' "$i"
  fi
  i=$((i + 2))
done

不要使用 expr。将你的数学表达式放在 (( )) 中(或 echo $(( )) 以打印结果),shell 将计算它。

查看 expr 输出与常规 shell 算法相比的结果:

$ expr 0+1
0+1
$ echo "$((0+1))"
1
如果两个操作数都不是整数,

-eqtest 或单个方括号(例如 [ 1 -eq 2 ])会打印错误。这就是导致您出错的原因。

这是在 bash 中列出素数的一种快速简洁的方法。你可以把它放在函数或脚本中:

for ((i=2; i<="${1:?Maximum required}"; i++)); do
    for ((j=2; j<i; j++)); do
        ((i%j)) || continue 2
    done
    echo "$i"
done

编辑:只是为了解释一下,如果 (([expression])) 计算为 0,它 returns 非零(1)(失败)。如果它的计算结果为任何其他数字(正数或负数),则它 returns 为零(真)。当一个数被 i 整除时,模数 (%)(余数)为零。因此命令失败,我们知道它不是素数,我们可以 continue 外循环,用于下一个数字。