行の中央にあるキーワードの後ろの対応する行から値のみを取得します。

行の中央にあるキーワードの後ろの対応する行から値のみを取得します。

こんにちは、ファイルの途中に次の行があり、「energy =」の後にある値を取得する必要があります。行番号は「lineNumber」という変数に格納されます。ファイルの構造は同じですが、値が異なる別の行があります。私は "lineNumber"で定義されたラインのエネルギー値だけが欲しいです。助けてくれてありがとう。ありがとうございます!

Properties=species:S:1:pos:R:3:velocities:R:3:forces:R:3:local_energy:R:1:fix_atoms:S:3 Lattice="42.0000000000       0.0000000000    0.0000000000    0.0000000000   46.0000000000    0.0000000000    0.0000000000    0.0000000000   50.0000000000" temperature=327.11679001 pressure=14.24003276 time_step=5.0000 time=5000.0000 energy=-18.022194 virial="0.46990039            0.48760331     -0.77576961      0.48760331      0.78141847      0.59471844     -0.77576961      0.59471844      0.64787347" stress="-0.00000486          -0.00000505      0.00000803     -0.00000505     -0.00000809     -0.00000616      0.00000803     -0.00000616     -0.00000671" volume=96600.000000 step=1000

答え1

Linuxベースのシステムを使用しているので、GNUを使用していることはほぼ確実です。grep

grep -oP 'energy=\K[^\s]+'

例えば

echo 'Properties=species:S:1:pos:R:3:velocities:R:3:forces:R:3:local_energy:R:1:fix_atoms:S:3 Lattice="…" temperature=327.11679001 … time=5000.0000 energy=-18.022194 virial="0.46990039 …" stress="…" volume=96600.000000 step=1000' |
    grep -oP 'energy=\K[^\s]+'

出力

-18.022194

次のようなものを使用できますsed

lineNumber=123
sed -n "${lineNumber}{p;q}" file

これらを総合すると、

sed -n "${lineNumber}{p;q}" file | grep -oP 'energy=\K[^\s]+'

次のものを使用することもできますperl

perl -e '
    $lineNumber = shift;                                 # Arg 1 is line number
    $fieldName = shift;                                  # Arg 2 is field name
    while (defined($line = <>)) {                        # Read lines from file or stdin
        next unless $. == $lineNumber;                   # Skip until required line
        chomp $line;                                     # Discard newline
        %a =                                             # Create key/value array. Read the next lines upwards
            map { split(/=/, $_, 2) }                    # 3. Split into {key,value} tuples
            grep { /=/ }                                 # 2. Only interested in assignments
            split(/(\w+=(".*?"|[^"].*?)\s+)/, $line);    # 1. Split line into « key=value » and « key="several values" » fields
        print $a{$fieldName}, "\n";                      # Print chosen field value
        exit 0
    }
' "$lineNumber" 'energy' file

答え2

awk -v lineNumber="$lineNumber" -v FS="energy=" 'NR == lineNumber {print $2}' FILE | awk '{print $1}'

答え3

現在の要件と比較して少し過剰になる可能性がありますが、ラベルと値のマッピング配列を作成できます(下記の配列に保存されていますf[])。

$ awk -v FPAT='[^=[:space:]]+=([^[:space:]]+|"[^"]*")' -v n="$lineNumber" '
    NR == n {
        delete f
        for (i=1; i<=NF; i++) {
            f[gensub(/=.*/,"",1,$i)] = gensub(/[^=]+=/,"",1,$i)
        }
        print f["energy"]
    }
' file
-18.022194

f[]その後、ラベル(名前)を使用してインデックスを作成して、値または値の組み合わせに対して必要な操作を実行できます。たとえば、次のように書くことができます。

awk -v FPAT='[^=[:space:]]+=([^[:space:]]+|"[^"]*")' '
    {
        delete f
        for (i=1; i<=NF; i++) {
            f[gensub(/=.*/,"",1,$i)] = gensub(/[^=]+=/,"",1,$i)
        }
    }
    (f["time"] < 6) && (f["volume"] > 8) {
        print f["temperature"], f["energy"], f["step"] / f["time_step"]
    }
' file
327.11679001 -18.022194 200

または比較/計算/印刷する必要がある他のすべて。

上記はGNU awkを使用してFPATsumを処理します。コードだけをもう少し追加すると、サポートされているgensub()POSIX awkを使用してほとんど(すべてではありません)と同じ操作を実行できます。delete array

$ awk -v n="$lineNumber" '
    NR == n {
        delete f
        rec = $0
        while ( match(rec,/[^=[:space:]]+=([^[:space:]]+|"[^"]*")/) ) {
            tag = val = substr(rec,RSTART,RLENGTH)
            sub(/=.*/,"",tag)
            sub(/[^=]+=/,"",val)
            f[tag] = val
            rec = substr(rec,RSTART+RLENGTH)
        }
        print f["energy"]
    }
' file
-18.022194

awkが苦情を示している場合は、その行をどのawkでも機能する行にdelete f変更してください。split("",f)

答え4

使用幸せ(以前のPerl_6)

~$ raku -ne 'put ++$ => $/ if ++$ == 1 && m/ \s energy\= <( <+ :N + [\-+.]>+  )> \s /;'   file

または:

~$ raku -ne 'put ++$ => $0 if ++$ == 1 && m/ \s energy\=  ( <+ :N + [\-+.]>+  )  \s /;'    file

または:

~$ raku -ne 'put ++$ => $<val> if ++$ == 1 && m/ \s energy\=  $<val>=<+ :N + [\-+.]>+   \s /;'   file

上記のRakuコードは、-ne自動印刷ではなく行単位のフラグを使用します(コードは入力ファイル内の行ごとに実行されます)。右から左に読み、m/.../次の必須値に一致するものを見つけますenergy=。この一致は、Unicodeの数字と文字、、が複数表示される<+ :N + [\-+.]>+複合文字クラスであるRaku Regex方言で書かれています(この構造ではバックスラッシュエスケープを必要とする数少ない文字の1つ)。この文字クラスを作成できますが、Unicode以外の数字との一致は失われます。:N-+.-<+[0..9\-+.]>+0..9

++$Rakuで行番号を計算する最も簡単な方法は、1から始まる自動インクリメントカウンタを実行することです。これを1つにまとめると(今すぐ左から右に読み取る)、最初のサンプルコードは次のようになります。「行番号が数値的に 1 に等しく、行番号putの後に組み込み++$$/一致変数がある場合、必要な一致が見つかり、キャプチャ タグを除くすべての項目が削除されます。」if ++$ == 1&&<( ... )>。ブール値は&&使用されるため短絡されます。 (++$ =>返す値が値だけの場合は、出力からその値を削除してください。)

サンプル入力(OPのデータは3回使用されます):

Properties=species:S:1:pos:R:3:velocities:R:3:forces:R:3:local_energy:R:1:fix_atoms:S:3 Lattice="42.0000000000       0.0000000000    0.0000000000    0.0000000000   46.0000000000    0.0000000000    0.0000000000    0.0000000000   50.0000000000" temperature=327.11679001 pressure=14.24003276 time_step=5.0000 time=5000.0000 energy=-18.022194 virial="0.46990039            0.48760331     -0.77576961      0.48760331      0.78141847      0.59471844     -0.77576961      0.59471844      0.64787347" stress="-0.00000486          -0.00000505      0.00000803     -0.00000505     -0.00000809     -0.00000616      0.00000803     -0.00000616     -0.00000671" volume=96600.000000 step=1000
Properties=species:S:1:pos:R:3:velocities:R:3:forces:R:3:local_energy:R:1:fix_atoms:S:3 Lattice="42.0000000000       0.0000000000    0.0000000000    0.0000000000   46.0000000000    0.0000000000    0.0000000000    0.0000000000   50.0000000000" temperature=327.11679001 pressure=14.24003276 time_step=5.0000 time=5000.0000 energy=-18.022194 virial="0.46990039            0.48760331     -0.77576961      0.48760331      0.78141847      0.59471844     -0.77576961      0.59471844      0.64787347" stress="-0.00000486          -0.00000505      0.00000803     -0.00000505     -0.00000809     -0.00000616      0.00000803     -0.00000616     -0.00000671" volume=96600.000000 step=1000
Properties=species:S:1:pos:R:3:velocities:R:3:forces:R:3:local_energy:R:1:fix_atoms:S:3 Lattice="42.0000000000       0.0000000000    0.0000000000    0.0000000000   46.0000000000    0.0000000000    0.0000000000    0.0000000000   50.0000000000" temperature=327.11679001 pressure=14.24003276 time_step=5.0000 time=5000.0000 energy=-18.022194 virial="0.46990039            0.48760331     -0.77576961      0.48760331      0.78141847      0.59471844     -0.77576961      0.59471844      0.64787347" stress="-0.00000486          -0.00000505      0.00000803     -0.00000505     -0.00000809     -0.00000616      0.00000803     -0.00000616     -0.00000671" volume=96600.000000 step=1000

出力例(タブ区切りの戻り):

1   -18.022194

lineNumber最後に、1行にハードコードするのではなくコマンドラインで入力したい場合は、envRakuは内部的に環境変数を動的ハッシュ変数として使用できます%*ENV。したがって、次のことができます(最初の文字envはオプションです)。

~$ env lineNumber="1" perl6 -ne 'put $0 if ++$ == %*ENV<lineNumber> && m/ \s energy\=  ( <+[0..9\-+.]>+ )  \s /;'   file
-18.022194

https://docs.raku.org/言語/regexes
https://raku.org

関連情報