Первый прототип с использованием старого доброго grep
и cut
:
grep ${VALUE} inputfile.csv | cut -d, -f${INDEX}
Если это достаточно быстро и дает правильный результат, все готово. :)
В файле CSV каждое поле разделяется запятой. Проблема в том, что само поле может иметь встроенную запятую:
Name,Phone
"Woo, John",425-555-1212
Вам действительно нужен пакет библиотеки, который предлагает надежную поддержку CSV, вместо того, чтобы полагаться на использование запятой в качестве разделителя полей. Я знаю, что такие языки сценариев, как Python, имеют такую поддержку. Однако мне хорошо знаком язык сценариев Tcl, поэтому я использую его. Вот простой сценарий Tcl, который выполняет то, о чем вы просите:
#!/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's 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
}
}
Сохраните этот сценарий в файле с именем csv.tcl и вызовите его как:
$ tclsh csv.tcl filename indexNumber expectedValue
Сценарий считывает файл CSV построчно и сохраняет строка в переменной $ line, затем она разбивает каждую строку на список столбцов (переменная $ columns). Затем он выбирает указанный столбец и присваивает его переменной $ columnValue. Если есть совпадение, распечатайте исходную строку.
CSV не все так просто. В зависимости от пределов имеющихся у вас данных вам, возможно, придется побеспокоиться о кавычках (которые могут содержать запятые и символы новой строки) и экранировании кавычек.
Так что, если ваши данные достаточно ограничены, можно обойтись простым разделением запятых, сценарий оболочки может сделать это легко. Если, с другой стороны, вам нужно «правильно» проанализировать CSV, то bash не будет моим первым выбором. Вместо этого я бы посмотрел на язык сценариев более высокого уровня, например Python с csv.reader .
index=1
value=2
awk -F"," -v i=$index -v v=$value '$(i)==v' file
Решение A sed
или awk
, вероятно, будет короче, но вот решение для Perl:
perl -F/,/ -ane 'print if $F[<INDEX>] eq "<VALUE>"`
где
отсчитывается от 0 (0 для первого столбца, 1 для 2-го столбца и т. д.)
В качестве альтернативы однострочникам на основе cut
- или awk
можно использовать специализированный csvtool
aka ocaml-csv
:
$ cat yourfile | csvtool -t ',' col "$index" - | grep "$value"
Согласно документации, он обрабатывает экранирование, цитирование и т. Д.
Использование 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
Боже ... с переменными и всем остальным, awk почти является настоящим языком программирования ...