2013-07-09 4 views
2

У меня есть труба | с разделителем.Подсчитайте количество столбцов в файле с разделителями каналов

Файл:

106232145|"medicare"|"medicare,medicaid"|789 

Я хотел бы подсчитать количество полей в каждой строке. Я попытался код ниже

Код:

awk -F '|' '{print NF-1}' 

Это возвращает меня результат как 5 вместо 4. Это происходит потому, что AWK принимает «Медикер | Medicaid» в двух различных областях вместо одного поля

+1

Единственный способ, которым я могу думать, что вы получили 5 вместо 4 с этой командой, - это если вы на самом деле делали 'awk -F \" ... '(или вместо двойной кавычки, один из других символов, который возникает 4 раза в строке, например 'd' или' i' ...). Фактически, с 'NF-1', вы должны были получить 3 вместо этого ... – twalberg

+0

Но ваш пример не содержит« medicare | medicaid » – runrig

+3

Если у вас есть данные, которые могут содержать разделитель в значениях указанного кавычки, вам нужен специализированный анализатор в формате CSV. Шансы - ['csvfix'] (http://code.google.com/p/csvfix/)) может делать то, что вам нужно. См. также [Инструмент Linux для анализа файлов CSV] (http://stackoverflow.com/questions/1063125/linux-tool-to-parse-csv-files). вполне вероятно, что у Python и Ruby тоже есть модули. –

ответ

6
awk -F\| '{print NF}' 

дает правильный результат.

+1

-1 - это прерывается, когда файл содержит трубы как часть поля (например, «medicare | medicaid»), который действителен в общих файлах с разделителями. – DVK

0

Для | разделителей файла с внедренным | в между этим GNU awk v4.0 или поздно должен работать:

gawk '{ print NF }' FPAT="([^|]+)|(\"[^\"]+\")" 
+0

-1 - это прерывается, когда файл содержит трубы как часть поля (например, , «medicare | medicaid»), который действителен в общих файлах с разделителями. – DVK

+0

@DVK Извините, хороший момент. Я обновил решение для строк со встроенными трубами. –

+0

Теперь попробуйте обновить его до учетной записи для двойных кавычек, являющихся частью текста поля, в котором ваша обновленная версия не работает) (возможно, с RegEx, может быть, но PAINFUL!) – DVK

-1

perl -ne 'print scalar(split(/\|/, $_)) . "\n"' [имя файла]

3

Чистый раствор Unix (без AWK/Perl):

$ cat /tmp/x1 
1|2|3|34 
4534|23442|1121|334434 

$ head -1 /tmp/x1 | tr "|" "\012" | wc -l 
4 

Perl, решение - 1-вкладыш:

$ perl5.8 -naF'\|' -e 'print scalar(@F)."\n";exit;' /tmp/x1 
4 

НО !!!! ВАЖНЫЙ!!!

Каждое из этих решений, а также ответы на другие ответы, НЕ работают на 100%!

А именно, все они ломаются, когда это реальный файл «труба отделенного», с трубой является допустимым символом в поле (и поле цитирует), как реальные CSV файлы работы.

E.g.

$ cat /tmp/x2 
"0|1"|2|3|34 
4534|23442|1121|334434 
$ perl5.8 -naF'\|' -e 'print scalar(@F)."\n";exit;' /tmp/x1 
5 <----- BROKEN!!! There are only 4 fields, first field is "0|1" 

Чтобы исправить это, правильный CSV (или файл с разделителями) синтаксический анализатор должен быть использован, например, один в Perl:

$ perl5.8 -MText::CSV_XS 
-ne '$csv=Text::CSV_XS->new({sep_char => "|"}); $csv->parse($_); 
print $csv->fields(); print "\n"; exit;' /tmp/x2 

печать правильное значение

4 

Как примечание, простое исправление решения awk или sed с извилистым RegEx не будет работать легко, так как поверх труб, содержащих-и-q uoted PSV, спецификация также позволяет котировки как часть поля. Это НЕ поддается хорошему решению RegEx.

+2

'tr',' head' и 'wc' больше не являются« чистыми unix », чем' awk' ... 'perl' - немного другая история ... – twalberg

+0

@twalberg - некоторые устаревшие разделенные unixes могут появиться без awk или Perl. Или установлены системы Windows с установленными пакетами Unix. – DVK

+1

Не могу не согласиться на 'perl', но' awk' является частью SUS, LSB и других подобных стандартов. Конечно, кто-то мог бы намеренно не устанавливать некоторые из основных пакетов, но это не делает их установку более «чистой» (и на самом деле может сделать ее более «сломанной») ... – twalberg

1
$ cat fieldparse.awk 
#NR > 1 { print "--"; } 

# Uncomment printf/print in the for loops to see 
# each field on a separate line as well as the commented line above (to show that it works). 
{ 
    nfields = 0; 
    for (i = 1; i <= NF; i++) { 
     if ($i ~ /^".*[^"]$/) 
      for (; i <= NF && ($i !~ /.*"$/); i++) { 
       #printf("%s%s", $i, FS); 
      } 
     #print $i; 
     nfields++; 
    } 
    print nfields; 
    if (FILENAME == "-") 
     FILENAME = "(standard input)"; 
    filenames[FILENAME] = sprintf("%d %d", FNR, nfields); 
} 

END { 
    print NR, "total records processed"; 
    for (f in filenames) { 
     split(filenames[f], fn, " "); 
     printf("\t* %s: %d records with %d fields\n", f, fn[1], fn[2]); 
    } 
} 

$ awk -F'|' -f fieldparse.awk demo.txt 

Он работает ни для одного разделителя символа, который не двойная кавычки, то есть стандартная табуляция, CSV и т.д. форматов (в стандартной комплектации, как они получают в любом случае ...)

Формата вывода просто иллюстративна и немного декоративна в конце, но контент по-прежнему полезен IMHO, например, обработка нескольких файлов. В любом случае, я надеюсь, что это поможет! :-)

Редактировать

Это была протестирована с помощью Мок и GNU AWK (Gawk), последний из которых был протестирован в традиционном, POSIX и режимов по умолчанию. Обрезайте комментарии и выводимые операторы, чтобы найти в нем небольшую программу, хотя она не такая маленькая, как хотелось бы.

Смежные вопросы