Подтвердить что ты не робот

Bash shell scripting - csv parsing

Я пытаюсь проанализировать CSV, содержащий потенциально 100k + строк. Вот критерии, которые у меня есть:

  • Индекс идентификатора
  • Значение идентификатора

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

Любые идеи, особенно учитывая производительность?

4b9b3361

Ответ 1

Первый прототип с использованием простых старых grep и cut:

grep ${VALUE} inputfile.csv | cut -d, -f${INDEX}

Если это достаточно быстро и дает правильный результат, все готово.:)

Ответ 2

В качестве альтернативы однострочным терминалам, основанным на cut - или awk, вы можете использовать специализированный csvtool aka ocaml-csv:

$ cat yourfile | csvtool -t ',' col "$index" - | grep "$value"

В соответствии с документами он обрабатывает экранирование, цитирование и т.д.

Ответ 3

Посмотрите это видео youtube: BASH урок для сценариев 10, работающий с файлами CSV

Файл CSV:

Bob Brown;Manager;16581;Main
Sally Seaforth;Director;4678;HOME

BASH script:

#!/bin/bash
OLDIFS=$IFS
IFS=";"
while read user job uid location
 do

    echo -e "$user \
    ======================\n\
    Role :\t $job\n\
    ID :\t $uid\n\
    SITE :\t $location\n"
 done < $1
 IFS=$OLDIFS

Вывод:

Bob Brown     ======================
    Role :   Manager
    ID :     16581
    SITE :   Main

Sally Seaforth     ======================
    Role :   Director
    ID :     4678
    SITE :   HOME

Ответ 4

CSV не так уж и прост. В зависимости от пределов данных, которые у вас есть, вам может понадобиться беспокоиться о цитируемых значениях (которые могут содержать запятые и новые строки) и экранировать кавычки.

Таким образом, если ваши данные достаточно ограничены, вы можете легко скомбинировать с запятой, оболочка script может сделать это легко. Если, с другой стороны, вам необходимо правильно проанализировать CSV, bash не будет моим первым выбором. Вместо этого я бы посмотрел на язык сценариев более высокого уровня, например Python с csv.reader.

Ответ 5

В CSV файле каждое поле разделяется запятой. Проблема в том, что само поле может иметь встроенную запятую:

Name,Phone
"Woo, John",425-555-1212

Вам действительно нужен пакет библиотеки, который предлагает надежную поддержку CSV вместо того, чтобы полагаться на использование запятой в качестве разделителя полей. Я знаю, что такие языки сценариев, как Python, имеют такую ​​поддержку. Тем не менее, мне нравится язык сценариев Tcl, поэтому я использую это. Вот простой Tcl script, который делает то, что вы просите:

#!/usr/bin/env tclsh

package require csv 
package require Tclx

# Parse the command line parameters
lassign $argv fileName columnNumber expectedValue

# Subtract 1 from columnNumber because Tcl list index starts with a
# zero instead of a one
incr columnNumber -1

for_file line $fileName {
    set columns [csv::split $line]
    set columnValue [lindex $columns $columnNumber]
    if {$columnValue == $expectedValue} {
        puts $line
    }   
}

Сохраните этот script в файл csv.tcl и вызовите его как:

$ tclsh csv.tcl filename indexNumber expectedValue

Объяснение

script считывает файл CSV по строке и сохраняет строку в переменной $line, затем разбивает каждую строку на список столбцов (переменные $столбцы). Затем он выбирает указанный столбец и присваивает его переменной $columnValue. Если есть совпадение, распечатайте исходную строку.

Ответ 6

Использование awk:

export INDEX=2
export VALUE=bar

awk -F, '$'$INDEX' ~ /^'$VALUE'$/ {print}' inputfile.csv

Изменить: В соответствии с отличным комментарием Денниса Уильямсона, это может быть гораздо более чисто (и безопасно) написано путем определения awk-переменных с использованием -v:

awk -F, -v index=$INDEX -v value=$VALUE '$index == value {print}' inputfile.csv

Jeez... с переменными и всем, awk почти реальный язык программирования...

Ответ 7

index=1
value=2
awk -F"," -v i=$index -v v=$value '$(i)==v' file

Ответ 8

В ситуациях, когда данные не содержат каких-либо специальных символов, решение, предложенное Nate Kohl и ghostdog74, является хорошим.

Если данные содержат запятые или новые строки внутри полей, awk может неправильно подсчитывать номера полей, и вы получите неправильные результаты.

Вы все еще можете использовать awk с некоторой помощью из программы, которую я написал, называемой csvquote (доступной в https://github.com/dbro/csvquote):

csvquote inputfile.csv | awk -F, -v index=$INDEX -v value=$VALUE '$index == value {print}' | csvquote -u

Эта программа находит специальные символы внутри указанных полей и временно заменяет их непечатаемыми символами, которые не будут путать awk. Затем они восстанавливаются после завершения awk.

Ответ 9

A sed или awk решение, вероятно, будет короче, но здесь для Perl:

perl -F/,/ -ane 'print if $F[<INDEX>] eq "<VALUE>"`

где <INDEX> основано на 0 (0 для первого столбца, 1 для второго столбца и т.д.)

Ответ 10

Я искал элегантное решение, поддерживающее цитирование, и не требовал установки каких-либо моментов в моем устройстве VMware vMA. Оказывается, этот простой python script делает трюк! (Я назвал script csv2tsv.py, так как он преобразует CSV в значения, разделенные табуляцией - TSV)

#!/usr/bin/env python

import sys, csv

with sys.stdin as f:
    reader = csv.reader(f)
    for row in reader:
        for col in row:
            print col+'\t',
        print

Значения, разделенные табуляцией, могут быть легко разделены с помощью команды вырезания (не нужно указывать разделитель, вкладка по умолчанию). Здесь пример использования/вывода:

> esxcli -h $VI_HOST --formatter=csv network vswitch standard list |csv2tsv.py|cut -f12
Uplinks
vmnic4,vmnic0,
vmnic5,vmnic1,
vmnic6,vmnic2,

В моих сценариях я фактически собираюсь анализировать вывод tsv по строкам и использовать чтение или вырезание, чтобы получить нужные мне поля.