Формат ввода не определена, но есть несколько простых способов, awk
, perl
и sqlite
.
(FNR==1) {
nocol=split(col,ocols,/,/) # cols contains named columns
ncols=split("vals " $0,cols) # header line
for (nn=1; nn<=ncols; nn++) colmap[cols[nn]]=nn # map names
OFS="\t" # to align output
for (nn=1; nn<=nocol; nn++) printf("%s%s",ocols[nn],OFS)
printf("\n") # output header line
}
(FNR>1) { # read data
for (nn=1; nn<=nocol; nn++) {
if (nn>1) printf(OFS) # pad
if (ocols[nn] in colmap) { printf("%s",$(colmap[ocols[nn]])) }
else { printf "--" } # named column not in data
}
printf("\n") # wrap line
}
$ nawk -f mycols.awk -v col=ID_3,ID_15 data
ID_3 ID_15
4 6
4 8
3 8
Perl, просто вариация на выше с некоторой PERL идиомы спутать/Развлекать:
use strict;
use warnings;
our @ocols=split(/,/,$ENV{cols}); # cols contains named columns
our $nocol=scalar(@ocols);
our ($nn,%colmap);
$,="\t"; # OFS equiv
# while (<>) {...} implicit with perl -an
if ($. == 1) { # FNR equiv
%colmap = map { $F[$_] => $_+1 } 0..$#F ; # create name map hash
$colmap{vals}=0; # name anon 1st col
print @ocols,"\n"; # output header
} else {
for ($nn = 0; $nn < $nocol; $nn++) {
print "\t" if ($nn>0);
if (exists($colmap{$ocols[$nn]})) { printf("%s",$F[$colmap{$ocols[$nn]}]) }
else { printf("--") } # named column not in data
}
printf("\n")
}
$ cols="ID_3,ID_15" perl -an mycols.pl < data
Это использует переменную среды, чтобы пропустить усилие разбора командной строки. Ему нужны параметры perl , которые устанавливают разделение поля и входной цикл чтения (как и awk).
И с sqlite
(я использовал v3.11, v3.8 или более поздней версии требуется для полезной .import
я считаю).Это использует временную базу данных в памяти (имя файла, если оно слишком велико для памяти, или для постоянной копии проанализированных данных), и автоматически создает таблицу на основе первой строки. Преимущества здесь в том, что вам может вообще не понадобиться никаких сценариев, и вы можете выполнять несколько запросов в своих данных только с одним служебным изложением анализа.
Вы можете пропустить следующий шаг, если у вас есть один жесткого язычок ограничивающих столбцы, в этом случае заменить .mode csv
с .mode tab
в SQLITE примера ниже. В противном случае, чтобы преобразовать данные в подходящий CSV-иш формат:
nawk -v OFS="," '(FNR==1){$0="vals " $0} {$1=$1;print} <data> data.csv
Это добавляет фиктивный первый столбец «Vals» в первую строку, а затем выводит каждую строку как разделенные запятые, он делает это казалось бы, бессмысленное назначение $1
, но это приводит к перерасчету $0
, заменяющему FS (пробел/табуляцию) OFS
(запятая).
$ sqlite3
sqlite> .mode csv
sqlite> .import data.csv mytable
sqlite> .schema mytable
CREATE TABLE mytable(
"vals" TEXT,
"ID_1" TEXT,
"ID_2" TEXT,
"ID_3" TEXT,
"ID_6" TEXT,
"ID_15" TEXT
);
sqlite> select ID_3,ID_15 from mytable;
ID_3,ID_15
4,6
4,8
3,8
sqlite> .mode column
sqlite> select ID_3,ID_15 from mytable;
ID_3 ID_15
---------- ----------
4 6
4 8
3 8
Использование .once
или .output
для отправки вывода в файл (sqlite docs). Используйте .headers on
или .headers off
при необходимости. sqlite вполне счастлив создать неназванный столбец, поэтому вам не нужно добавлять имя в первый столбец строки заголовка, но вам нужно убедиться, что количество столбцов одинаково для всех строк ввода и форматов ,
Если в течение .import
вы получили «ожидаемые столбцы X, но обнаружили ошибки Y», вам потребуется немного очистить формат данных.
См., Например, http://unix.stackexchange.com/questions/25138/how-to-print-certain-columns-by-name –