スクリプトのためのBash演算子

スクリプトのためのBash演算子

個別に連携する2つのスクリプトがありますが、一緒に機能させる方法がわかりません。

使命は、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

2番目のスクリプトは

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

elif 

答え1

スクリプトは、最初のコマンドライン引数を別の変数として選択し、コマンドライン引数のリストからop削除します。

#!/bin/sh

op=$1
shift

このスクリプトをadd 1 2 3引数として使用すると、コードは文字列addをに割り当ててop保持します。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

最後の2回の呼び出しに注意してください。最後は数字を提供しないので、2番目はshift失敗します。 2番目の呼び出しは、ジョブが不明であることを知らせ、早期に終了します。

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

これらのエラーメッセージの正確な形式は、システム内のシェルの役割によって異なります/bin/sh

答え2

最初のスクリプトは繰り返されます$@。オペランドを追加するには、最初のパラメータ(op=$1)を保存してからを使用しますshift

からman bash

シフト[n]
n+1 ...の位置パラメータ名が$ 1 ...に変更されました。 $#から$#-n+1までの数値で表されるパラメータは設定されません。 n は、$# 以下の負以外の数字でなければなりません。 nが0の場合、パラメータは変更されません。 n を指定しない場合、1 とみなされます。 nが$#より大きい場合、位置パラメータは変更されません。 n が $# より大きいか 0 より小さい場合、戻り状態は 0 より大きく、それ以外の場合は 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 3たり test.sh '*' 1 2 3

'*'ファイル名に拡張されないように引用符で囲む必要があります。)


しかし、私はループの代わりにbcandを使いたいです。$IFS$(( ... )))

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

また見なさい:

"$*"単一の単語に展開します"$1c$2c..."。これは通常c空白ですが、実際にはの最初の文字なので、必要に応じてIFS指定できます。

関連情報