awkまたはsedを使用して列内で算術演算を実行する

awkまたはsedを使用して列内で算術演算を実行する

算術結果に統合したい単純な算術方程式を含む列を持つファイルがあります。

入力サンプル(タブで区切られた列):

+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つのうち、数字と文字のシーケンスを探し、+それをインタプリタの算術プロセッサ(evalin 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

関連情報