テキストファイルのソートキーの選択に問題があります。

テキストファイルのソートキーの選択に問題があります。

次のテキストファイルがあるとしましょう。

e8:b4:c8:b2:d8:b9                       "Biswas Gautam"                   2016            me            Mob
ec:8e:b5:f8:a2:12                       "Dipin Gyawali"                   2015            me            Lan
f0:27:65:70:91:62                       "Karan Rai"                       2016            cs            Mob
f0:de:f1:33:33:32                       "Dipendra L. Karki"               2015            me            Lan

私の項目(機械工学)やcs(コンピュータサイエンス)などの配置を3番目の列(年)、4番目の列、名前で並べ替えたいと思います。

しかし、2番目の列名は問題を引き起こします。時には中間名があり、元のソリューションと競合します。だから二重引用符がトリックを実行すると思います。しかし、二重引用符内のスペースを無視する方法がわかりません。

sort -k 4 -k 5 -k 2 -kfilename

空白が3つあるので4つを書きました。 1つは列のため、1つはフルネーム(名前[空白]性)のために発生します。

このように並べ替える方法はありますか?

答え1

ファイル形式が示されているとおりに厳密に指定されている場合は、sort特定の列をキーとして使用する必要があります。

sort -k1.75,1.78n -k1.91,1.92 -k1.105,1.107 -k1.41,1.74 input

...サンプル入力を次に変換します。

f0:de:f1:33:33:32                       "Dipendra Karki"                  2015            me            Lan
ec:8e:b5:f8:a2:12                       "Dipin Gyawali"                   2015            me            Lan
f0:27:65:70:91:62                       "Karan Rai"                       2016            cs            Mob
e8:b4:c8:b2:d8:b9                       "Biswas Gautam"                   2016            me            Mob

答え2

$ sed -E 's/ {3,}/@/g' file | sort -t @ -k3,3 -k5,5 | sed 's/@/    /g'
ec:8e:b5:f8:a2:12    "Dipin Gyawali"    2015    me    Lan
f0:de:f1:33:33:32    "Dipendra Karki"    2015    me    Lan
e8:b4:c8:b2:d8:b9    "Biswas Gautam"    2016    me    Mob
f0:27:65:70:91:62    "Karan Rai"    2016    cs    Mob

これにより、3つ以上のスペースがその文字に置き換えられます@(データにないすべての文字が機能します)。

次に、sort入力を@別々のフィールドとして解釈し、3番目のフィールド(年)と5番目のフィールド(デバイス)にソートするように指示します。最後にソートされたデータの各スペースを4つのスペースに置き換えますsed。ここにリテラルタブを挿入するか、GNUを使用できます。@\tsed

より美しい:

$ sed -E 's/ {3,}/@/g' file | sort -t @ -k3,3 -k5,5 | column -s @ -t
ec:8e:b5:f8:a2:12  "Dipin Gyawali"   2015  me  Lan
f0:de:f1:33:33:32  "Dipendra Karki"  2015  me  Lan
e8:b4:c8:b2:d8:b9  "Biswas Gautam"   2016  me  Mob
f0:27:65:70:91:62  "Karan Rai"       2016  cs  Mob

以下は、awk各列を左揃えの20文字幅の文字列としてフォーマットするために使用されます。

$ sed -E 's/ {3,}/@/g' file | sort -t @ -k3,3 -k5,5 | awk -F@ '{ for (i=1;i<=NF;++i) printf("%-20s",$i); print "" }'
ec:8e:b5:f8:a2:12   "Dipin Gyawali"     2015                me                  Lan
f0:de:f1:33:33:32   "Dipendra Karki"    2015                me                  Lan
e8:b4:c8:b2:d8:b9   "Biswas a Gautam"   2016                me                  Mob
f0:27:65:70:91:62   "Karan Rai"         2016                cs                  Mob

あるいは、個別にフォーマットすることもできます。

$ sed -E 's/ {3,}/@/g' file | sort -t @ -k3,3 -k5,5 | awk -F@ '{ printf("%s %-30s %-30s %-30s %s\n", $1,$2,$3,$4,$5) }'
ec:8e:b5:f8:a2:12 "Dipin Gyawali"                2015                           me                             Lan
f0:de:f1:33:33:32 "Dipendra Karki"               2015                           me                             Lan
e8:b4:c8:b2:d8:b9 "Biswas a Gautam"              2016                           me                             Mob
f0:27:65:70:91:62 "Karan Rai"                    2016                           cs                             Mob

答え3

間隔を正確に保つには(形式を再指定するのではなく、コサロナンダの答え)正確な列位置に依存したくない(例:ジェフ・シャラーの答え)、次のPerlスクリプトが動作します。

#!/usr/bin/perl
use 5.022;

my @dat;
while (<<>>) {
    #          0     1      2        3     4     5     6     7     8
    #          mac   sp     name     sp    yr    sp    dpt   sp    net
    my @m = /^(\S+) (\s+) "([^"]+)" (\s+) (\S+) (\s+) (\S+) (\s+) (\S+)$/x
        or die "invalid line: $_";
    push @dat, \@m;
}

@dat = sort {
    $a->[4] <=> $b->[4] || $a->[6] cmp $b->[6] || $a->[2] cmp $b->[2]
} @dat;

foreach (@dat) {
    print join('', @$_), "\n";
}

Perl v5.22.0以降を<<>>演算子として使用します。これを使用する場合は、以前のバージョンのPerlでも機能する必要があります<>。このプログラムには基本的に3つの「段落」があります。最初の段落は正規表現を使用して行を解析し、使用された正確な間隔もキャプチャします。 2番目の段落では、データをソートします。 3番目の段落はそれを再印刷します。

答え4

別の方法は、各空白文字を次のように置き換えることです。〜サイプレースホルダ@で引用符を囲んでソートし、@文字を空白に戻します。

perl -pe 's#("[^"]*")#$1 =~ s/ /@/rg#eg' filename | sort -k 3 -k 4 -k 2 | sed 's/@/ /g'

関連情報