我正在编写一个 shell 脚本,它可以在我的本地 /bin/sh
上正常运行(在 Ubuntu 13.04 上破折号),但我最终需要在一个哑盒子上运行它,在那里我得到一个由于对变量进行操作而出错:
$((n2 - n1 + 1))
不起作用,我收到如下错误:
syntax error: you disabled math support for $((arith)) syntax
我不太了解那里的sh
,但我认为这个东西是busybox。我怎样才能在这个愚蠢的 shell 上做数学题?
编辑小程序列表
~ # busybox --list
[
arp
ash
cat
chgrp
chmod
chown
chroot
chvt
clear
cmp
cp
cut
date
dd
deallocvt
df
dmesg
du
echo
env
false
find
freeramdisk
ftpget
ftpput
grep
gunzip
gzip
hexdump
hwclock
ifconfig
ln
losetup
ls
md5sum
mkdir
mkfifo
mknod
mkswap
more
mount
mv
nslookup
ping
ping6
ps
pwd
renice
reset
rm
rmdir
route
seq
sh
sha1sum
sha256sum
sleep
sort
swapoff
swapon
switch_root
sync
tar
taskset
tee
telnet
test
tftp
time
top
touch
true
umount
uname
uniq
uptime
usleep
vconfig
vi
wget
whoami
yes
最佳答案
使用 seq
+grep
+sort
进行通用加法/减法/乘法/除法
注释:
- 所有这些都符合 POSIX 标准,但有一个速度稍快的非 POSIX
subtract_nonposix
,它依赖于支持-w
的grep
和-B
(非 POSIX,但甚至busybox
'grep
支持它们) add
/subtract
仅支持无符号整数作为输入乘
/除
支持有符号整数作为输入减
/乘
/除
可以处理负结果- 根据输入
乘
/除
可能会非常昂贵(见评论)
如果不这样做, subtract
/multiply
可能会污染您的命名空间(它们分别使用$__x
和$__y
)在子 shell 中使用
arith.sh
:
#!/bin/sh
is_uint()
{
case "$1" in
''|*[!0-9]*) return 1
;;
esac
[ "$1" -ge 0 ]
}
is_int()
{
case "${1#-}" in
''|*[!0-9]*) return 1
;;
esac
}
# requires seq, grep -n, sort -nr
# reasonably fast
add()
{
if ! is_uint "$1" \
|| ! is_uint "$2"; then
echo "Usage: add <uint1> <uint2>"
return 1
fi
[ "$1" -eq 0 ] && { echo "$2"; return; }
[ "$2" -eq 0 ] && { echo "$1"; return; }
{
seq 1 "$1"
seq 1 "$2"
} \
| grep -n "" \
| sort -nr \
| { read num; echo "${num%[-:]*}"; }
}
# requires seq, grep -n, sort -nr, uniq -u
# reasonably fast
subtract()
{
if ! is_uint "$1" \
|| ! is_uint "$2"; then
echo "Usage: subtract <uint1> <uint2>"
return 1
fi
if [ "$1" -ge "$2" ]; then
__x="$1"
__y="$2"
else
__x="$2"
__y="$1"
fi
{
seq 0 "${__x}"
seq 0 "${__y}"
} \
| sort -n \
| uniq -u \
| grep -n "" \
| sort -nr \
| \
{
read num
: ${num:=0}
[ "${__x}" = "$2" ] && [ "$1" -ne "$2" ] && minus='-'
echo "${minus}${num%:*}"
}
}
# requires seq, grep -wB
# faster than subtract(), but requires non-standard grep -wB
subtract_nonposix()
{
if ! is_uint "$1" \
|| ! is_uint "$2"; then
echo "Usage: subtract <uint1> <uint2>"
return 1
fi
if [ "$1" -ge "$2" ]; then
__x="$1"
__y="$2"
else
__x="$2"
__y="$1"
fi
seq 0 "${__x}" \
| grep -w -B "${__y}" "${__x}" \
| \
{
read num
[ "${__x}" = "$2" ] && [ "$1" -ne "$2" ] && minus='-'
echo "${minus}${num}"
}
}
# requires seq, sort -nr, add()
# very slow if multiplicand or multiplier is large
multiply()
{
if ! is_int "$1" \
|| ! is_int "$2"; then
echo "Usage: multiply <int1> <int2>"
return 1
fi
[ "$2" -eq 0 ] && { echo 0; return; }
# make sure to use the smaller number for the outer loop
# to speed up things a little if possible
if [ $1 -ge $2 ]; then
__x="$1"
__y="$2"
else
__x="$2"
__y="$1"
fi
__x="${__x#-}"
__y="${__y#-}"
seq 1 "${__y}" \
| while read num; do
sum="$(add "${sum:-0}" "${__x}")"
echo "${sum}"
done \
| sort -nr \
| \
{
read num
if [ "$1" -lt 0 -a "$2" -gt 0 ] \
|| [ "$2" -lt 0 -a "$1" -gt 0 ]; then
minus='-'
fi
echo "${minus}${num}"
}
}
# requires subtract()
# very costly if dividend is large and divisor is small
divide()
{
if ! is_int "$1" \
|| ! is_int "$2"; then
echo "Usage: divide <int1> <int2>"
return 1
fi
[ "$2" -eq 0 ] && { echo "division by zero"; return 1; }
(
sum="${1#-}"
y="${2#-}"
count=
while [ "${sum}" -ge "${y}" ]; do
sum="$(subtract "${sum}" "${y}")"
# no need to use add() for a simple +1 counter,
# this is way faster
count="${count}."
done
if [ "$1" -lt 0 -a "$2" -gt 0 ] \
|| [ "$2" -lt 0 -a "$1" -gt 0 ]; then
minus='-'
fi
echo "${minus}${#count}"
)
}
echo "10 4 14
4 10
10 10
2 -2
-2 -2
0 0
x y" | while read x y; do
for op in add subtract subtract_nonposix multiply divide; do
printf -- "${x} ${y} %-17s = %s\n" "${op}" "$("${op}" "${x}" "${y}")"
done
echo
done
运行示例:
$ ./arith.sh
10 4 add = 14
10 4 subtract = 6
10 4 subtract_nonposix = 6
10 4 multiply = 40
10 4 divide = 2
4 10 add = 14
4 10 subtract = -6
4 10 subtract_nonposix = -6
4 10 multiply = 40
4 10 divide = 0
10 10 add = 20
10 10 subtract = 0
10 10 subtract_nonposix = 0
10 10 multiply = 100
10 10 divide = 1
2 -2 add = Usage: add <uint1> <uint2>
2 -2 subtract = Usage: subtract <uint1> <uint2>
2 -2 subtract_nonposix = Usage: subtract <uint1> <uint2>
2 -2 multiply = -4
2 -2 divide = -1
-2 -2 add = Usage: add <uint1> <uint2>
-2 -2 subtract = Usage: subtract <uint1> <uint2>
-2 -2 subtract_nonposix = Usage: subtract <uint1> <uint2>
-2 -2 multiply = 4
-2 -2 divide = 1
0 0 add = 0
0 0 subtract = 0
0 0 subtract_nonposix = 0
0 0 multiply = 0
0 0 divide = division by zero
x y add = Usage: add <uint1> <uint2>
x y subtract = Usage: subtract <uint1> <uint2>
x y subtract_nonposix = Usage: subtract <uint1> <uint2>
x y multiply = Usage: multiply <int1> <int2>
x y divide = Usage: divide <int1> <int2>
关于shell - 在一个非常愚蠢的 shell 中添加/减去变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16331116/