Если у меня есть файл csv, есть ли быстрый способ bash распечатать содержимое только одного столбца? Можно с уверенностью предположить, что каждая строка имеет одинаковое количество столбцов, но каждое содержимое столбца будет иметь разную длину.
Как извлечь один столбец из CSV файла
Ответ 1
Вы можете использовать awk для этого. Измените "$ 2" на нужный вам столбец.
awk -F "\"*,\"*" '{print $2}' textfile.csv
Ответ 2
да. cat mycsv.csv | cut -d ',' -f3
напечатает третий столбец.
Ответ 3
Самый простой способ, которым я смог это сделать, - просто использовать csvtool. У меня были и другие варианты использования csvtool, и он может обрабатывать кавычки или разделители соответственно, если они появляются в самих данных столбца.
csvtool format '%(2)\n' input.csv
Замена 2 номером столбца будет эффективно извлекать данные столбца, которые вы ищете.
Ответ 4
Приземлился здесь, чтобы извлечь из файла, разделенного вкладкой. Думаю, я бы добавил.
cat textfile.tsv | cut -f2 -s
Где -f2
извлекает 2, ненулевой проиндексированный столбец или второй столбец.
Ответ 5
Многие ответы на эти вопросы велики, а некоторые даже смотрят в угловые случаи. Я хотел бы добавить простой ответ, который может быть использован в повседневной жизни... где вы чаще всего попадаете в эти угловые случаи (например, с помощью пропущенных запятых или запятых в кавычках и т.д.).
FS (полевой разделитель) - это переменная, значение которой неверно пространство. Таким образом, awk по умолчанию разбивает пространство в любой строке.
Таким образом, используя BEGIN (Выполнять перед вводом), мы можем установить это поле для чего угодно...
awk 'BEGIN {FS = ","}; {print $3}'
Вышеприведенный код напечатает третий столбец в файле csv.
Ответ 6
Другие ответы работают хорошо, но поскольку вы попросили решение, используя только оболочку bash, вы можете сделать это:
AirBoxOmega:~ d$ cat > file #First we'll create a basic CSV
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
И затем вы можете вытащить столбцы (первый в этом примере) следующим образом:
AirBoxOmega:~ d$ while IFS=, read -a csv_line;do echo "${csv_line[0]}";done < file
a
1
a
1
a
1
a
1
a
1
a
1
Итак, здесь происходит несколько вещей:
-
while IFS=,
- это означает использование запятой в качестве IFS (Internal Field Separator), которое использует оболочка для определения того, что разделяет поля (блоки текста). Поэтому, говоря, что IFS =, похоже на то, что "a, b" совпадает с "a b", если IFS = "" (что и есть по умолчанию). -
read -a csv_line;
- это говорит, что читайте в каждой строке по одному и создавайте массив, в котором каждый элемент называется "csv_line", и отправляйте его в раздел "do" нашего цикла while -
do echo "${csv_line[0]}";done < file
- теперь мы находимся в фазе "do", и мы говорим echo о 0-ом элементе массива "csv_line". Это действие повторяется в каждой строке файла. Часть< file
просто сообщает цикл while, из которого следует читать. ПРИМЕЧАНИЕ: помните, что в bash массивы индексируются 0, поэтому первый столбец является 0-м элементом.
Итак, у вас есть это, вытащив столбец из CSV в оболочке. Другие решения, вероятно, более практичны, но этот чист bash.
Ответ 7
Вы можете использовать GNU Awk, см. в этой статье руководства пользователя.
В качестве улучшения для решения, представленного в статье (в июне 2015 года), следующая команда gawk позволяет использовать двойные кавычки в двойных кавычках; двойная кавычка отмечена двумя последовательными двойными кавычками (""). Кроме того, это позволяет пустые поля , но даже это не может обрабатывать многострочные поля. Следующий пример печатает третий столбец (через c=3
) textfile.csv:
#!/bin/bash
gawk -- '
BEGIN{
FPAT="([^,\"]*)|(\"((\"\")*[^\"]*)*\")"
}
{
if (substr($c, 1, 1) == "\"") {
$c = substr($c, 2, length($c) - 2) # Get the text within the two quotes
gsub("\"\"", "\"", $c) # Normalize double quotes
}
print $c
}
' c=3 < <(dos2unix <textfile.csv)
Обратите внимание на использование dos2unix
для преобразования возможных разрывов строк в стиле DOS (CRLF, т.е. "\ r\n" ) и кодировки UTF-16 (с байтом), в "\n" и UTF-8 (без байта знак заказа), соответственно. Стандартные CSV файлы используют CRLF в качестве разрыва строки, см. Wikipedia.
Если на входе могут быть многострочные поля, вы можете использовать следующий script. Обратите внимание на использование специальной строки для разделения записей на выходе (так как новая строка разделителя по умолчанию может возникать в записи), Опять же, следующий пример печатает третий столбец (через c=3
) textfile.csv:
#!/bin/bash
gawk -- '
BEGIN{
RS="\0" # Read the whole input file as one record;
# assume there is no null character in input.
FS="" # Suppose this setting eases internal splitting work.
ORS="\n####\n" # Use a special output separator to show borders of a record.
}
{
nof=patsplit($0, a, /([^,"\n]*)|("(("")*[^"]*)*")/, seps)
field=0;
for (i=1; i<=nof; i++){
field++
if (field==c) {
if (substr(a[i], 1, 1) == "\"") {
a[i] = substr(a[i], 2, length(a[i]) - 2) # Get the text within
# the two quotes.
gsub(/""/, "\"", a[i]) # Normalize double quotes.
}
print a[i]
}
if (seps[i]!=",") field=0
}
}
' c=3 < <(dos2unix <textfile.csv)
Существует другой подход к проблеме. csvquote может выводить содержимое файла CSV, модифицированного таким образом, чтобы специальные символы в поле были преобразованы, чтобы обычные инструменты обработки текста Unix могли использоваться для выберите определенную колонку. Например, следующий код выводит третий столбец:
csvquote textfile.csv | cut -d ',' -f 3 | csvquote -u
csvquote
может использоваться для обработки произвольных больших файлов.
Ответ 8
[dumb @one pts] $cat > file # Сначала мы создадим базовый CSV
а, б, в, г, д, е, ж, з, I, K
1,2,3,4,5,6,7,8,9,10
а, б, в, г, д, е, ж, з, I, K
1,2,3,4,5,6,7,8,9,10
[dumb @one pts] $awk -F, '{print $1}' файл
1
1
Ответ 9
Мне нужно было правильно разбирать CSV, а не cut
/awk
и молиться. Я пытаюсь это сделать на Mac без csvtool
, но csvtool
поставляется с ruby, так что вы можете сделать:
echo "require 'csv'; CSV.read('new.csv').each {|data| puts data[34]}" | ruby
Ответ 10
csvtool col 2 file.csv
где 2 - интересующий вас столбец
Вы также можете сделать
csvtool col 1,2 file.csv
сделать несколько столбцов
Ответ 11
Вы не можете сделать это без полного анализатора CSV.
Ответ 12
Интересно, почему ни один из ответов до сих пор не упомянул csvkit.
csvkit - это набор инструментов командной строки для преобразования и работы с CSV
Я использую его исключительно для управления данными CSV и до сих пор я не нашел проблему, которую я не мог решить с помощью cvskit.
Чтобы извлечь один или несколько столбцов из файла cvs, вы можете использовать утилиту csvcut
которая является частью набора инструментов. Чтобы извлечь второй столбец, используйте эту команду:
csvcut -c 2 filename_in.csv > filename_out.csv
Если строки в csv заключены в кавычки, добавьте символ кавычки с опцией q
:
csvcut -q '"' -c 2 filename_in.csv > filename_out.csv
Установите с помощью pip install csvkit
или sudo apt install csvkit
.
Ответ 13
Вот пример CSV файла с 2 столбцами
myTooth.csv
Date,Tooth
2017-01-25,wisdom
2017-02-19,canine
2017-02-24,canine
2017-02-28,wisdom
Чтобы получить первый столбец, используйте:
cut -d, -f1 myTooth.csv
f обозначает поле, а d обозначает разделитель
Выполнение вышеуказанной команды приведет к следующему выводу.
Выход
Date
2017-01-25
2017-02-19
2017-02-24
2017-02-28
Чтобы получить только 2-й столбец:
cut -d, -f2 myTooth.csv
И вот выходной вывод
Tooth
wisdom
canine
canine
wisdom
incisor
Другой вариант использования:
Ваш входной файл CSV содержит 10 столбцов, и вы хотите столбцы со 2 по 5 и столбцы 8, используя запятую в качестве разделителя ".
cut использует -f (что означает "поля") для указания столбцов и -d (что означает "разделитель") для указания разделителя. Вы должны указать последнее, потому что некоторые файлы могут использовать пробелы, табуляции или двоеточия для разделения столбцов.
cut -f 2-5,8 -d , myvalues.csv
cut - это командная утилита, и вот еще несколько примеров:
SYNOPSIS
cut -b list [-n] [file ...]
cut -c list [file ...]
cut -f list [-d delim] [-s] [file ...]
Ответ 14
Некоторое время, используя этот код, он не "быстро", если не считать "вырезание и вставка из stackoverflow".
Он использует операторы ${##} и ${%%} в цикле вместо IFS. Он вызывает "err" и "die" и поддерживает только запятую, тире и трубку как символы SEP (все, что мне нужно).
err() { echo "${0##*/}: Error:" "[email protected]" >&2; }
die() { err "[email protected]"; exit 1; }
# Return Nth field in a csv string, fields numbered starting with 1
csv_fldN() { fldN , "$1" "$2"; }
# Return Nth field in string of fields separated
# by SEP, fields numbered starting with 1
fldN() {
local me="fldN: "
local sep="$1"
local fldnum="$2"
local vals="$3"
case "$sep" in
-|,|\|) ;;
*) die "$me: arg1 sep: unsupported separator '$sep'" ;;
esac
case "$fldnum" in
[0-9]*) [ "$fldnum" -gt 0 ] || { err "$me: arg2 fldnum=$fldnum must be number greater or equal to 0."; return 1; } ;;
*) { err "$me: arg2 fldnum=$fldnum must be number"; return 1;} ;;
esac
[ -z "$vals" ] && err "$me: missing arg2 vals: list of '$sep' separated values" && return 1
fldnum=$(($fldnum - 1))
while [ $fldnum -gt 0 ] ; do
vals="${vals#*$sep}"
fldnum=$(($fldnum - 1))
done
echo ${vals%%$sep*}
}
Пример:
$ CSVLINE="example,fields with whitespace,field3"
$ $ for fno in $(seq 3); do echo field$fno: $(csv_fldN $fno "$CSVLINE"); done
field1: example
field2: fields with whitespace
field3: field3
Ответ 15
Вы также можете использовать цикл
IFS=,
while read name val; do
echo "............................"
echo Name: "$name"
done<itemlst.csv
Ответ 16
Я думаю, что проще всего использовать csvkit:
Получает 2-й столбец:
csvcut -c 2 file.csv
Однако есть также csvtool и, возможно, ряд других инструментов csv bash:
sudo apt-get install csvtool
(для систем на основе Debian)
Это вернет столбец с первой строкой, в которой есть "ID".
csvtool namedcol ID csv_file.csv
Это вернет четвертый ряд:
csvtool col 4 csv_file.csv
Если вы хотите удалить строку заголовка:
csvtool col 4 csv_file.csv | sed '1d'