算術結果に統合したい単純な算術方程式を含む列を持つファイルがあります。
入力サンプル(タブで区切られた列):
+104-1+12 6 +3
各列内の算術合計を計算したいと思います。列に算術記号が含まれていない場合は、+
項目の前に が含まれているかのように処理されます。+
列がunsignedで始まる場合、sedを介してシンボルを追加するのは簡単ですが(sed -E 's/(\t)([0-9]*)/\1\t+\2/g'
例のように行が数字で始まらないと仮定すると機能します)
私の予想結果は次のとおりです。
115 6 3
Unixでどのようにこれを達成できますか? awk/sed ソリューションが推奨されます。
答え1
あなたが使用できるperl
:
perl -pe 's/[\d+-]+/eval$&/ge' your-file
でも:
perl -pe 's/[\d+-]+/$&/gee' ファイル(Rakesh に感謝)
zsh
同じ
set -o extendedglob # for the ## operator (same as ERE +)
while IFS= read -r line; do
printf '%s\n' ${line//(#m)[0-9+-]##/$((MATCH))}
done < your-file
または:
zmodload zsh/mapfile
set -o extendedglob
printf %s ${mapfile[your-file]//(#m)[0-9+-]##/$((MATCH))}
-
これらの4つのうち、数字と文字のシーケンスを探し、+
それをインタプリタの算術プロセッサ(eval
in perl
(またはee
代替拡張をperl
コードとして評価するフラグ)、$((...))
in zsh
)に渡します。
式をインタプリタに渡す前に検証しないため、エラーが発生する可能性があります(たとえば、-+-
同じシーケンスで3++
)。ただし、少なくとも数字と-
/+
文字のみが考慮されるため、報告されたエラーよりも多くのエラーは発生しません。メッセージを送信してコマンドを中断します。
答え2
繰り返さない「sed」を追加答え; awkでも方法が見つかりませんでしたが、ここにbashバージョンがあります。
while IFS= read -r line
do
set -f; set -- $line
for e in "$@"
do
printf "%d " "$(( e ))"
done
echo
done < input
答え3
sed -E 's/(\t)([0-9])/\1+\2/g' data.file |
while IFS= read -r l; do
set -f; IFS=$'\t'
printf '0%s\n' $l | bc -l | paste -s -
done
sed -e 's/\t\([0-9]\)/\t+\1/' data.file |
while IFS= read -r l; do
set -f; IFS=$'\t'
printf '0%s\n' $l | bc -c |
sed -ne '
$!{
y/:@irKW/ /
s/[^ 0-9]/ & /g
s/[ ][ ]*/ /g;s/^[ ]*//;s/[ ]*$/p/p
}
' | dc | paste -s -
done
ここでは、数学的表現の表現を生成し、postfix
それを後置計算機に渡す前に、dc
コマンド出力から非数学的情報を整理しますbc -c
。
結果
115 6 3
答え4
以下は、外部実行可能ファイルを使用せずに数値の文字列表現を数値表現としてマーシャリングするawkの機能を利用するすべてのawkソリューションです。
awk -F"\t" \
'BEGIN { OFS="\t" }
{ gsub(/-/,"|-")
gsub(/\+/,"|")
for(i=1; i<=NF; i++) { ## iterate over columns
num_parts=split($i,parts,"|")
for(j=1; j<=num_parts; j++) ## iterate over arithmetic expression parts
sums[i] += parts[j]+0 ## Adding zero marshals the string into a numeric
}}
END{
for(i=1; i<=NF; i++) {
if(i>1) printf OFS
printf sums[i]
}
print "" }' file