用于脚本编写的 Bash 运算符

用于脚本编写的 Bash 运算符

我有两个脚本可以单独协同工作,但我不知道如何使它们协同工作

任务是使 bash 脚本接受运算符和整数列表,并让命令执行操作。

我基本上需要能够使用脚本

test.sh add 1 2 3
5
test.sh sub 4 2 1
1

我的第一个脚本是

for var in $@
do

sum=$(( sum + var ))
done
echo $sum

第二个脚本是

if [ $operator = add ]; then
add= echo $(($a+$b))

elif 

答案1

一个脚本将其第一个命令行参数挑选到一个名为的单独变量中op,然后将其从命令行参数列表中删除:

#!/bin/sh

op=$1
shift

如果使用此脚本add 1 2 3作为参数调用,则代码会将字符串分配addop并将其保留1 2 3"$@".

然后我们可以循环剩余的命令行参数:

#!/bin/sh

op=$1
shift

for arg do
    # some commands should go here
done

添加的循环将确保变量arg将依次获取每个剩余命令行参数的值。我们也可以像这样编写循环的开头,for arg in "$@"; do ...但是需要更多的键入,并且程序员有时会忘记在 周围添加引号$@

根据值的不同,$op循环中可能会发生多个操作之一。我们可以通过一个简单的测试来看看$op是什么并进行正确的操作。无论如何,下面会累积一些值acc,并且该acc值应该(根据问题中命令的呈现方式)初始化为第一个数字,并且该数字也需要从参数列表中移出。

#!/bin/sh

op=$1
shift

acc=$1
shift

for arg do
    case $op in
        add) acc=$(( acc + arg )) ;;
        sub) acc=$(( acc - arg )) ;;
        mul) acc=$(( acc * arg )) ;;
        div) acc=$(( acc / arg )) ;; # note: integer division here
        *)
            printf 'Unknown operation: %s\n' "$op" >&2
            exit 1
    esac
done

printf '%s\n' "$acc"

保存脚本并使其可执行后测试该脚本:

$ ./script add 1 2 3
6
$ ./script sub 4 2 1
1
$ ./script xor a b c
Unknown operation: xor
$ ./script add
script[7]: shift: nothing to shift

请注意最后两次调用。最后一个未能提供任何数字,因此第二个shift失败。倒数第二个调用注意到操作未知并提前终止。

通过稍微更改 的赋值op和初始化acc,我们可以使错误消息稍微更有用:

#!/bin/sh

op=${1:?Expected operator}
shift

acc=${1:?Expected number}
shift

for arg do
    case $op in
        add) acc=$(( acc + arg )) ;;
        sub) acc=$(( acc - arg )) ;;
        mul) acc=$(( acc * arg )) ;;
        div) acc=$(( acc / arg )) ;; # note: integer division here
        *)
            printf 'Unknown operation: %s\n' "$op" >&2
            exit 1
    esac
done

printf '%s\n' "$acc"

再次测试:

$ ./script
script[3]: 1: Expected operator
$ ./script add
script[6]: 1: Expected number
$ ./script add 1 2
3

这些错误消息的确切格式可能会有所不同,具体取决于 shell 在您的系统上的作用/bin/sh

答案2

你的第一个脚本正在循环$@,如果你想添加一个操作数,你可以保存第一个参数(op=$1)然后使用shift

man bash

移位[n]
n+1 ... 中的位置参数被重命名为 $1 ...。由数字 $# 到 $#-n+1 表示的参数未设置。 n 必须是小于或等于 $# 的非负数。如果 n 为 0,则不更改任何参数。如果未给出 n,则假定为 1。如果 n 大于 $#,则位置参数不会更改。如果 n 大于 $# 或小于零,则返回状态大于零;否则为 0。

$result使用第一个参数进行初始化,然后shift再次使用。

另外,请务必引用$@在运行循环时引用(这里)。

#!/bin/bash
op=$1
shift
result=$1
shift
for var in "$@"; do
  result=$(( result $op var ))
done
echo "$result"

您还可以shift一步完成:

op=$1
result=$2
shift 2

运行test.sh + 1 2 3test.sh '*' 1 2 3...

'*'必须加引号,以免扩展为文件名)。


但是,我宁愿使用bcand$IFS而不是循环 and$(( ... )))为此:

#!/bin/bash
OLDIFS="$IFS"
IFS=$1
shift
bc <<< "scale=5; $*"
IFS=$OLDIFS

也可以看看:

"$*"扩展为单个单词"$1c$2c..."。通常c是一个空格,但它实际上是 的第一个字符IFS,因此它可以是您选择的任何内容。

相关内容