Wyodrębnij określone kolumny z oddzielonego pliku za pomocą Awk

Przepraszam, jeśli to zbyt proste. Mam plik csv, gdzie kolumny mają wiersz nagłówka (v1, v2, itp.). Rozumiem, że aby wyodrębnić Kolumny 1 i 2, muszę zrobić: awk -F "," '{print $1 "," $2}' infile.csv > outfile.csv. Ale co jeśli będę musiał wyodrębnić kolumny od 1 do 10, 20 do 25 i 30, 33? Jako dodatek, czy jest jakiś sposób, aby wyodrębnić bezpośrednio z nazw nagłówków, a nie z numerów kolumn?

 28
Author: jww, 2011-10-22

8 answers

Nie wiem czy da się zrobić zakresy w awk. Możesz zrobić pętlę for, ale musisz dodać obsługę, aby odfiltrować kolumny, których nie chcesz. Chyba łatwiej to zrobić:

awk -F, '{OFS=",";print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$20,$21,$22,$23,$24,$25,$30,$33}' infile.csv > outfile.csv

Coś innego do rozważenia - a to szybsze i bardziej zwięzłe:

cut -d "," -f1-10,20-25,30-33 infile.csv > outfile.csv

Jeśli chodzi o drugą część twojego pytania, prawdopodobnie napisałbym skrypt w Perlu, który wie, jak obsługiwać wiersze nagłówków, analizując nazwy kolumn ze standardowego wejścia lub pliku, a następnie filtrując. On prawdopodobnie narzędzie, które chciałbym mieć do innych rzeczy. Nie jestem pewien, co do robienia w jednym linerze, chociaż jestem pewien, że da się to zrobić.

 47
Author: Cliff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-22 03:09:18

Jak wspomniał @Tom, podejście cut i awk faktycznie nie działa dla CSV z cytowanymi ciągami. Alternatywą jest moduł Pythona, który dostarcza narzędzie wiersza poleceń csvfilter. Działa jak cut, ale poprawnie obsługuje cytowanie kolumny CSV:

csvfilter -f 1,3,5 in.csv > out.csv

Jeśli masz Pythona (i powinieneś), możesz go zainstalować po prostu tak:

pip install csvfilter

Proszę zauważyć, że indeksowanie kolumn w csvfilter zaczyna się od 0(w przeciwieństwie do awk, który zaczyna się od $1). Więcej informacji na https://github.com/codeinthehole/csvfilter/

 10
Author: studgeek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-04 11:49:15

Inni odpowiedzieli na twoje wcześniejsze pytanie. Za to:

Jako dodatek, czy jest jakiś sposób na wyodrębnienie bezpośrednio z nazw nagłówków, a nie z numerów kolumn?

Nie próbowałem go, ale można przechowywać indeks każdego nagłówka w hash, a następnie użyć tego hasha, aby uzyskać jego indeks później.

for(i=0;i<$NF;i++){
    hash[$i] = i;
}

Potem użyj go:

j = hash["header1"];
print $j;
 3
Author: Ritesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-25 04:40:28

Inne języki mają skróty dla zakresów numerów pól, ale nie awk, będziesz musiał napisać swój kod jako swój strach; -)

awk -F, 'BEGIN {OFS=","} { print $1, $2, $3, $4 ..... $30, $33}' infile.csv > outfile.csv

Nie ma bezpośredniej funkcji w awk, która używałaby nazw pól jako określeń kolumn.

Mam nadzieję, że to pomoże.
 2
Author: shellter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-22 03:05:34

Możesz użyć pętli for, aby zaadresować pole za pomocą $i :

ls -l | awk '{for(i=3 ; i<8 ; i++) {printf("%s\t", $i)} print ""}'
 2
Author: Raymond Hettinger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-22 06:11:47

Tabulator jest zestawem uniksowych narzędzi wiersza poleceń do pracy z plikami csv, które mają linie nagłówka. Oto przykład wyodrębnienia kolumn według nazwy z pliku test.csv:

name,sex,house_nr,height,shoe_size
arthur,m,42,181,11.5
berta,f,101,163,8.5
chris,m,1333,175,10
don,m,77,185,12.5
elisa,f,204,166,7

Następnie tblmap -k name,height test.csv tworzy

name,height
arthur,181
berta,163
chris,175
don,185
elisa,166
 1
Author: stefan.schroedl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-04 07:52:40

Jeśli Perl jest opcją:

perl -F, -lane 'print join ",",@F[0,1,2,3,4,5,6,7,8,9,19,20,21,22,23,24,29,32]'

-a autosplits line into @F Fields array. Indeksy zaczynają się od 0 (nie 1 Jak w awk)
-F, separatorem pola jest,

Jeśli plik CSV zawiera przecinki w cudzysłowach, pełnowartościowe parsery CSV, takie jak Perl Text::CSV_XS, są specjalnie stworzone do obsługi tego rodzaju dziwactwa.

perl -MText::CSV_XS -lne 'BEGIN{$csv=Text::CSV_XS->new()} if($csv->parse($_)){@f=$csv->fields();print (join ",",@f[0,1,2,3,4,5,6,7,8,9,19,20,21,22,23,24,29,32])}'

Podałem więcej wyjaśnień w mojej odpowiedzi tutaj: parse csv file using gawk

 0
Author: Chris Koknat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:17:44

Nie używam awk, ale najprostszym sposobem, w jaki udało mi się to zrobić, było użycie csvtool. Miałem również inne przypadki użycia, Aby użyć csvtool i może obsługiwać cudzysłowy lub ograniczniki odpowiednio, jeśli pojawiają się one w samych danych kolumn.

csvtool format '%(2)\n' input.csv
csvtool format '%(2),%(3),%(4)\n' input.csv

Zastąpienie 2 numerem kolumny skutecznie wyodrębni dane kolumny, których szukasz.

 0
Author: Samar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-25 18:39:27