2016-04-13 8 views
0

私はラインを持つファイルがあります:浮動小数点フィールドの編集AWKの空白での保存/埋め込み?

CH1 12.30 4.800 12 !

私は特定のフィールドを置き換えたい...と言う$2[0.0,1.0)に選ばれた浮動小数点スカラーでスケーリングし、いくつかの同等とします。しかし、元の長さを維持するために、10進数と同じ数を保持し、さらにフロントエンドをスペースで埋めたいと思っています。

私はいくつかの組み合わせを考えていますlen/gsub/printfawkがこれを達成できます。私は現在試みているものの例として


scalar=0.00; echo 'CH1 12.30 4.800 12 !' | awk -v sc=$scalar '/CH1/{gsub(/[0-9]*\.[0-9]*/,$2*sc,$2);} {print;}'

出力:

CH1 0 4.800 12 !

は出力: が正しくスケール#を出力しますが、スペースがないだけで、フィールド$2から取り除かれ、ライン全体です。

scalar=0.00; echo 'CH1 12.30 4.800 12 !' | awk -v sc=$scalar '/CH1/{gsub(/$2/,$2*sc,$0);} {print;}'

出力:

CH1 12.30 4.800 12 !

注: は何もしません!出力は変更されません。

仮定:

  1. フィールド$2$3は同じかもしれないが、私は唯一のフィールド$2を変更したいです。
  2. フィールド$1には英数字のみが含まれます。
  3. フィールド$2および$3は、任意の10進数の桁数を持つ浮動小数点数です。通常、桁数は[1,4]です。全体の部分は3桁を超えません。
  4. フィールド$4は、[8,99]の整数です。
  5. フィールド$4以降の文字はすべてコメントであり、特殊文字を含む場合があります。

私は空白の保存に関するいくつかの質問に遭遇してきた同様の質問を検索し、それらは私にいくつかのアイデアを与えた...しかし、私は実際には小数点以下を保つために、空白文字を追加したいので、私のは少し異なっています実際には行の同じ場所にロックされ、ユーザーの書式設定を目的のファイルに保存することができます。 /$2/リテラル$2文字列を探しているので、フィールド2である(そして、我々は一つだけなので、無地subで十分に変化しているので、gsubはやり過ぎであるものは何でもとは対照的に、

+0

あなたは '.... | awk -v sc = "$スカラー" ... '、そうですか?がんばろう。 – shellter

+1

書式を扱うだけの余分なロジックを構築しているようです。あなたの計算ステップをパイプを介してフォーマットステップに渡すことで、フォーマットを管理するだけの簡単な方法はありません。 (たぶんあなたはある時点で幅を変えたいと思うでしょう)、つまり '... | awk -v sc = "$スカラー" ... | awk '{printf( "%8s%10s%-06s \ n"、$ 1、$ 2、$ 3)} "です。ちょうどアイデア。がんばろう。 – shellter

+0

合理的なアプローチのようだ...私はちょうどawkでこれを行うより管理しやすい方法があるかどうか疑問に思っていた。 –

答えて

1

gsub(/$2/,...)式には、失敗したが、gsubはここに無害です。)

それは正規表現ではなく、文字列リテラル)として扱われることになるだろうが、我々は、スラッシュなし(ただ$2を使用することができます。

$ scalar=0.00; echo 'CH1  12.30  4.800  12 !' | 
    awk -v sc=$scalar '/CH1/{gsub($2,$2*sc);} {print;}' 
CH1  0  4.800  12 ! 

これはあまりにも小数点以下のものを失うので、まだないが、私たちが望んでいるものの、あなたのアプローチがうまくいくことを示しています。 sprintf()は(私たちは12.30を取得したいと思うものです)"%5.2f"のような形式の指示に従った文字列を生成することができますことを、私たちが行う必要があるすべては、フィールド$2の合計の長さと長さを把握さを考えると

小数部(.の後)は、splitlengthを使用すると簡単です。リテラル52の代わりに、*を使用して整数引数を抽出できるので、置換文字列の作成は最初のように簡単です。したがって:

$ cat foo.sh 
#! /bin/sh 

scalar=0.00 
echo 'CH1  12.30  4.800  12 !' 
echo 'CH1  12.30  4.800  12 !' | 
    awk -v sc=$scalar ' 
$2 ~ /[0-9]*\.[0-9]*/ { 
    split($2, parts, /\./) 
    ofraclen = length(parts[2]) 
    repl = sprintf("%*.*f", length($2), ofraclen, $2 * sc) 
    sub(/[0-9]*\.[0-9]*/, repl) 
} 
{print} 
' 
$ sh foo.sh 
CH1  12.30  4.800  12 ! 
CH1   0.00  4.800  12 ! 

我々はフィールドがまだ並んでいることを見ることができるように、私は余分なechoに入れます。 $2が適切に分割されることが保証されるように、一致基準を$2 ~ ...に変更しました。整数部分と小数部分に分割し、小数部分の長さを取得し、置換文字列を生成して、subを浮動小数点数の最初のオカレンスに使用します(フィールド$1が一致しない場合にのみ安全です。 $ 1の一致のテストがない場合は、subが間違っています)。

(私は実際には各ステートメントの後にセミコロンが好きですが、厳密には必要ではないのでここですべてを取りました)また、partsを保持しているほとんどの一時変数は削除できますが、理解する)

+0

これはOP特有のケースでは機能しますが、言及したように '$ 1'に浮動小数点数が含まれている場合に失敗するだけでなく、'スカラー 'による乗算によって数値が生成された場合にも失敗します(例えば 'スカラー= 9'で試してみる)、 '$ 2'の代わりに' $ 3'を実行したければ '$ 2'がsub()にマッチします。 –

+1

@エモートン:同意。スカラー値が[0.0,1.0]であることを指定しました。 (負のスケールファクターも列を混乱させます。) – torek

1

これは、いくつかのフィールド(複数可)上で動作した後、出力の入力からパディングを再現する一般的なアプローチです。

$ cat tst.awk 
NR==1 { 
    # Find the width of each space-padded, right-aligned field: 
    rec = $0 
    for (i=1; i<=NF; i++) { 
     match(rec,/[^[:space:]]+/) 
     w[i] = RSTART - 1 + RLENGTH 
     rec = substr(rec,w[i]+1) 
    } 

    # Find the precision of the target field: 
    match($2,/\..*/) 
    p = RLENGTH - 1 
} 

{ 
    # print the original just for comparison 
    print 

    # do the math: 
    $2 = sprintf("%.*f", p, $2 * scalar) 

    # print the updated record: 
    for (i=1;i<=NF;i++) { 
     printf "%*s", w[i], $i 
    } 
    print "" 
} 

$ awk -v scalar=0 -f tst.awk file 
CH1  12.30  4.800  12 ! 
CH1   0.00  4.800  12 ! 

$ awk -v scalar=0.5 -f tst.awk file 
CH1  12.30  4.800  12 ! 
CH1   6.15  4.800  12 ! 

$ awk -v scalar=9 -f tst.awk file 
CH1  12.30  4.800  12 ! 
CH1  110.70  4.800  12 ! 

上記スカラまたは浮動小数点フィールドの値は、あなたがどんな$1の値は変更しない(必要に応じて簡単に微調整があまりにも小数のフィールドに動作するように)としたいのかに関係なく動作します。

関連する問題