スペースで区切られた数値を含む変数セットがあります。最初の数値はスペースで区切ることもできます。例:
VAR=" 2 1 34 3 2 "
これらの数値をすべて合計する必要があります。最も簡単な方法は、数値間のすべてのスペースを+
で置き換え、bcでパイプすることです。
Forループ、paste、およびbcでそれを行うことができますが、おそらく誰かがそれを行う簡単な方法を知っていますか?多分いくつかの計算は、bash組み込み文字列置換を使用してVAR
のbashで直接行いますか?
$ for i in $VAR;do echo $i;done|paste -sd+|bc
42
更新:すべての提案に対するThx、配列を使用した非常に短いメソッドが最終的に見つかりました:
$ VAR=" 2 1 34 3 2 "
$ arr=( $VAR );echo "$((${arr[@]/%/+}0))"
42
$ VAR="$VAR -14"
$ arr=( $VAR );echo "$((${arr[@]/%/+}0))"
28
$
パラメータ展開を使用します。
#!/bin/bash
VAR=" 2 1 34 3 2 "
shopt -s extglob # Enable the `+(...)` construct.
expression=${VAR#+(\ )} # Remove leading spaces.
expression=${expression%+(\ )} # Remove trailing spaces.
bc <<< ${expression//+(\ )/+} # Replace strings of spaces by pluses.
いくつかのPerlトリック:
$ Perl -lane '$t+=$_ for @F; print $t' <<<"$var"
42
または
$ Perl -pe 's/(\d)\s+(?=\d)/$1+/g' <<<"$var" | bc
42
または
$ Perl -lane 'print eval join "+", @F' <<<"$var"
42
またはGNU sed
およびcoreutils:
$ tr -s ' ' '+' <<<$var | sed 's/^+//; s/+$//' | bc
42
Chrisの配列ソリューションと同様:
$ var=" 2 1 34 3 2 "
$ var=$(echo $var); echo "$((${var// /+}))"
42
すべてのスペース文字をトリミングしてスクイーズしてから、すべてのスペース文字を+
に置き換えて評価します。
ソース文字列にスペースと先頭/末尾のスペースが繰り返されています。
単純なスペースの_+
_への変換は失敗します:
_$ value=' 2 1 34 3 2 '
$ echo "${value// /+}"
++++++2+1++34+3++++2++++
_
すべての繰り返されたスペースを折りたたむand先頭/末尾のスペースを削除するには、引用符で囲まれていない変数のエコー(またはprintf)が必要です(IFSがデフォルトであると想定)。
_value=$(echo $value)
echo "${value// /+}"
2+1+34+3+2
_
そして、それはbcにフィードすることができます:
_$ echo "${value// /+}" | bc
42
_
必要な場合は、すべて1行で:
value=$(echo $value); echo "${value// /+}" | bc
または、sed
をフィルターとして使用することもできます(追加の変数はありませんが、低速です)。
_echo $value | sed 's/ /+/g' | bc
_
_<<<
_を使用した以前の試みには問題がありました:
_$ ~/bin/b44sh -c 'value=" 2 1 34 3 2 ";sed "s/ /+/g" <<<$value'
++++++2+1++34+3++++2++++
_
バージョン4.4以降のbash。以前のバージョンでは次のように機能しました:
_~/bin/b43sh -c 'value=" 2 1 34 3 2 ";sed "s/ /+/g" <<<$value'
2+1+34+3+2
_
Bash(およびsed)のどのバージョンでも実行できます(非常に堅牢なバージョンですが、外部ユーティリティ-sed
を呼び出します):
_sed "s/ \+/+/g" <<<"0 $value 0" | tee /dev/tty | bc
0+2+1+34+3+2+0
42
_
純粋なシェルソリューション(置換_${//}
_部分にbash、kshまたはzshが必要)は次のようになります。
value=$(echo $value); bc <<<"${value// /+}
さらにrobust(仮定を適用する™)およびportableバージョン:
(…)
_を使用します。*
_ et all(set -f)を展開しないことを確認します。+
_(IFS = +)で結合されていることを確認してください。_( IFS=" "; set -f; set -- $value; IFS=+; echo "$*" | bc; )
_
機能バージョン
1-シェルがlocal
を許可しない場合は、より遅いサブシェルフォームを使用します
2-一部(正しくはPOSIXで)は、引用符で囲まれていない_$*
_の使用について文句を言うかもしれません。
sum(){ local IFS=" "; set -f; set -- $*; IFS=+; echo "$*" | bc; }
多くの方法で引数を追加します
_$ value=" 2 1 34 3 2 "
$ sum "$value"
42
$ sum $value # beware of glob chars *, ? and [ and of odd IFS=123 settings
42
$ sum " 2 1 34 3 2 "
42
$ sum " 2" "1 " "34 3" " 2 "
42
$ var=23
$ sum " 2" "1 " "34 3" " 2 " "$var"
65
_
bashスクリプト:
$ v="2 4 7 10 3"
$ s=0
$ for i in $v
> do
> s=$((s+i))
> done
$ echo $s
26
変数の長さがわかっている場合は、次のようにawkを使用できます。
echo $VAR | awk '{print $1 + $2 + $3 + $4 + $5}'
出力:
42
これがお役に立てば幸いです。
構成要素の数値が整数である限り、これも機能します(これは、declare
またはtypeset
が整数式を初期化する算術式を受け入れるためです)
VAR=" 2 1 34 3 2 "
read -r VAR <<<$VAR #shed leading and trailing spaces, compact internal spaces
VAR=${VAR// /+} #replace spaces with plusses
declare -i var=$VAR #typeset var to an integer
echo $var
42