列の値が等しくない場合、その行のみを印刷する方法は?

列の値が等しくない場合、その行のみを印刷する方法は?

遺伝子型計算用の大容量入力ファイルがあります。最初の数行は次のとおりです。

LocusID f nAlleles x y
2L:8347 1 2 44.3166 -12.2373
2L:8347 1 2 39.2667 -6.8333
2L:31184 1 2 39.2667 -6.8333
2L:31184 1 2 39.2667 -6.8333
2L:42788 1 2 39.2667 -6.8333
2L:42788 1 2 39.2667 -6.8333
2L:42887 1 2 39.2667 -6.8333
2L:42887 1 2 39.2667 -6.8333

最初の列はサイトIDであり、各サイトに同じサイトIDを持つ2行があります。 x列とy列は、各軌跡に対して資格のない列だけを維持したいと思います。

これは上記の例で私が望む結果です。

out
2L:8347 1 2 44.3166 -12.2373
2L:8347 1 2 39.2667 -6.8333

どうすればいいのかご存知ですか?

答え1

$ cat tst.awk
NR == 1 {
    for (i=1; i<=NF; i++) {
        f[$i] = i
    }
    next
}
NR % 2 {
    split(prev,p)
    if ( ( p[f["x"]] != $(f["x"]) ) || ( p[f["y"]] != $(f["y"]) ) ) {
        print prev
        print
    }
}
{ prev = $0 }

$ awk -f tst.awk file
2L:8347 1 2 44.3166 -12.2373
2L:8347 1 2 39.2667 -6.8333

答え2

テスト済みです。列ヘッダーがファイルにない場合は、BEGIN行を削除します。

#! /bin/bash

AWK='''
BEGIN { getline; }
{
    R1 = $0; getline R2;
    split (R1, V1); split (R2, V2);
    if (V1[4] != V2[4] || V1[5] != V2[5]) {
        print R1; print R2;
    }
}
'''

    awk "${AWK}" myFile

答え3

おそらくEd Mortonのレビューですが、あまりにも膨大で、おそらくより一般的な注意を引くでしょう。

私は2つの役に立たないコメントを見て、仕事を始めることができないOPのために簡単な5分の仕事を書きました。次のような嘔吐を引き起こす代替手段を含むあなたの参考資料にはあまり興味がありません。

awk 'c&&!--c;/3/{c=5}/4/{print "Eureka!"}' file

私はより良いスキルが可能であることを指摘し、コードを投稿してテストしました。

もちろん、ここではgetl​​ineは必要ありませんが、操作にある程度対称性を与えます。 awkループに依存している場合は、FNR%2 == 1のようなものを使用して厳密に交互の行を処理します。これは迷惑なので、一般性のためにOP「2行」を無視し、LocusIDで行をグループ化することをお勧めします。

私はawkスクリプトがより読みやすいので、シェル変数に公開することによってそのスクリプトを上品にします。私はコマンドラインにたくさんのawkコードがあり、奇妙な場所に折りたたまれているのが嫌いです。また、これはawk全体がps -efに表示され、出力が破損するためシステム管理者に影響します(SunOSでは最大行長が固定されているためpsを競合するために使用されます)。

Bashでこれを防ぐための私の一般的なイディオムは次のとおりです。

awk -f <( echo "${AWK}" )

psはこれをawk -f /dev/fd/63としてリストし、好奇心から独自のコードを便利に隠します。

私はawkからシェルコマンドを分離しません。私は.awkファイルを使用しません。 2つの悪いことの1つが発生します。

(a).awkファイルを提供し、ユーザーがawkコマンド(おそらく「-F |」または他のオプションを含む)を入力すると予想すると、エラーが発生します。

(b)ユーザーに.shと.awkを提供しましたが、ファイル間で矛盾が発生する更新の問題があります。

同様に、マニュアルページを提供する必要がある場合は、ここにドキュメントを含む「Usage」と「Help」という関数で、それをスクリプト自体に含めます。

私は'''...'''が必要ないことをよく知っています.しかし、私は一重引用符の解決策を投稿するのに疲れました。人々に「そこに抜けた引用文があるので修正します」と考えさせ、テスト投稿を台無しにして動作しないと文句を言うことです。いくつかの空の文字列で難読化すると、人々がむやみに扱うのを防ぎ、視認性が向上します。

40年間Unixを使ってみると、シェルとawkの予約変数について知りました。私は良い命名規則を持っていますが、小さな質問については、OPが直感的に使用できる用語を使用することを好みます。 2本の線、2本のベクトル。私は可視性を高め、キーワードと区別するために多くのシェル変数に大文字を使用します。誰でもキーワードを書くことができます。ほとんどすべてのエラーは、コーダーがデータを見ず、変数の役割を強調しないために発生します。

Getlineは何を期待すべきかを知っているので、予期しない方法で失敗しません。私が使用するイディオムが気に入らないかもしれませんが、それが間違っているという意味ではありません。それは私が長年見てきた問題に対する解決策です。

答え4

私の提案:スペースをカンマで置き換えてCSVを作成し、データベースにロードします。

psql次のようにPostgresと提供されたファイルを使用してくださいtemp.csv

postgres=> create temp table d (locusid text, f int, n_alleles int, x float, y float);
CREATE TABLE
postgres=> \copy d from program 'tr " " , < temp.csv' with (format csv, header true)
COPY 8
postgres=> table d;
 locusid  | f | n_alleles |    x    |    y     
----------+---+-----------+---------+----------
 2L:8347  | 1 |         2 | 44.3166 | -12.2373
 2L:8347  | 1 |         2 | 39.2667 |  -6.8333
 2L:31184 | 1 |         2 | 39.2667 |  -6.8333
 2L:31184 | 1 |         2 | 39.2667 |  -6.8333
 2L:42788 | 1 |         2 | 39.2667 |  -6.8333
 2L:42788 | 1 |         2 | 39.2667 |  -6.8333
 2L:42887 | 1 |         2 | 39.2667 |  -6.8333
 2L:42887 | 1 |         2 | 39.2667 |  -6.8333
(8 rows)

postgres=> select d.* from d join d as d2 on d.locusid = d2.locusid and (d.x != d2.x or d.y != d2.y);
 locusid | f | n_alleles |    x    |    y     
---------+---+-----------+---------+----------
 2L:8347 | 1 |         2 | 44.3166 | -12.2373
 2L:8347 | 1 |         2 | 39.2667 |  -6.8333
(2 rows)

関連情報