Bashスクリプトを使用して、各行の最大値(列ヘッダー値または最初の行の同じ列値)を使用して列名を抽出しようとしています。次のコマンドを使用してCSVファイルの各行から最大値を抽出していますが、最大値で列名を印刷する方法が見つかりませんでした。
awk -F ',' '{max=$'$col1';for (i=1;i<=NF;i++) {if ($i > max){max=$i}};print " max: " max}' "$INPUT_PATH/tmp.csv" >>$INPUT_PATH/max1.csv
例:
サンプルCSVデータ:
col1,col2,col3,col4
1,5,2,6
4,0,1,2
1,2,0,0
0,0,7,0
希望の出力:
col4 6 2
col1 4 1
col2 2 2
col3 7 3
上記のコマンドにこれを行う方法はありますか、またはCSVファイルから必要な情報を抽出するより良い方法はありますか?
答え1
ミラーの使用(https://github.com/johnkerl/miller)と実行
mlr --c2n merge-fields -a max -r "^[a-z]" -o value -k then put '
for (key, value in $*) {
if (value == $value_max && key != "value_max") {
$fieldName=key;
}
}' then cut -f fieldName,value_max then reorder -f fieldName,value_max input.csv
あなたはやる
col4 6
col1 4
col2 2
col3 7
答え2
使用tr
とdatamash
:
tr , '\t' < file.csv | datamash -H max 1-4 | datamash transpose
出力:
max(col1) 4
max(col2) 5
max(col3) 7
max(col4) 6
メモ:
先行が不要な場合は、
sed
一部を使用して出力をクリーンアップできます。max()
列の数を特に知ることはできませんが、確かに大きな数より少ない場合に置き換え、
1-4
必要1-1000
に応じてゼロを追加します。正確な数を得るには
4
、$(head -1 file.csv | tr , ' ' | wc -w)
または(を使用して)に置き換えます。POSIX殻)$(read x < file.csv; echo ${x##*l};)
。整理と正確な計算により、結果として見苦しいコードは次のようになります。
tr , '\t' < file.csv | datamash -H max 1-$(read x < file.csv; echo ${x##*l};) | datamash transpose | sed 's/.*(\|)//g'
出力:
col1 4 col2 5 col3 7 col4 6
答え3
mx=0
レコードのすべてのフィールドが負の場合、初期値設定ソリューションは失敗します。安全に設定する$1
と、フィールドが@Peter.Oのように繰り返されることがあります。
楽しく、カウンターとループを生成するのではなく、配列インデックスをawk
繰り返すいくつかのバリエーションがあります。head
awk -F',' '
NR==1{split($0,head,FS); next}
{x=1; for (h in head) if ($h>$x) x=h;print head[x], $x }
' file
出力
col4 6
col1 4
col2 2
col3 7
答え4
CSVの問題は、通常のシェルツールではうまく解析できないことです。彼らはそれをうまくできません。それできるマイナーなケースではできますが、実際にはスクリプト言語が作業ツールです。
私はperl
もっと個人的に考えています。
#!/usr/bin/env perl
use strict;
use warnings;
use Text::CSV;
my $csv = Text::CSV->new();
open ( my $input, "<", "your_file.csv" ) or die $!;
$csv->column_names( $csv->getline( $input ) );
while ( my $row = $csv->getline_hr( $input ) ) {
my ( $highest, @rest ) = sort { $row->{$b} <=> $row->{$a} } keys %$row;
print join( "\t", $highest, $row->{$highest} ), "\n";
}
入力として使用される場合:
first,second,third,fourth
1,3,4,5,
5,4,3,2,
1,1,4,1,
以下を印刷します。
fourth 5
first 5
third 4