次のテキストファイルがあるとしましょう。
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を使用できます。@
\t
sed
より美しい:
$ 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'