Якщо у мене є файл csv, чи існує швидкий спосіб башти, щоб надрукувати вміст будь-якого одного стовпця? Можна впевнено припустити, що кожен рядок має однакову кількість стовпців, але вміст кожного стовпця матиме різну довжину.
Якщо у мене є файл csv, чи існує швидкий спосіб башти, щоб надрукувати вміст будь-якого одного стовпця? Можна впевнено припустити, що кожен рядок має однакову кількість стовпців, але вміст кожного стовпця матиме різну довжину.
Відповіді:
Ви можете використати awk для цього. Змініть "$ 2" на n-й стовпець, який ви хочете.
awk -F "\"*,\"*" '{print $2}' textfile.csv
gawk -F"|" "{print $13}" files*.csv
...,"string,string",...
"
і закінчиться останньою"
awk -F "\"*;\"*" '{print $2}' textfile.csv
так. cat mycsv.csv | cut -d ',' -f3
надрукує 3-й стовпчик.
awk
Найпростіший спосіб, коли мені вдалося це зробити, було просто використовувати csvtool . У мене були й інші випадки використання csvtool, і він може обробляти лапки або роздільники, якщо вони відображаються в самих даних стовпців.
csvtool format '%(2)\n' input.csv
Заміна 2 на номер стовпця ефективно витягує дані стовпців, які ви шукаєте.
cat input.csv | csvtool formath '%(2)\n' -
примітки. Я знаю, що кішка тут марна, але підпорядковуйте її будь-якій команді, яка звичайно експортує файл csv.
format '%(2)\n'
команда не могла сказати, де закінчується одне поле. (csvtool 1.4.2)
csvtool
здається, вимагають використання -
в якості вхідного імені файлу для читання з stdin.
csvtool format '%(1),%(10)\n' - < in.csv > out.csv
Приземлився тут, шукаючи витяг із файлу, розділеного вкладками Думав, я додам.
cat textfile.tsv | cut -f2 -s
Де -f2
витягує 2, ненульовий індексований стовпець або другий стовпчик.
cat
зайвий:< textfile.tsv cut -f2 -s
Багато відповідей на ці питання чудові, а деякі навіть заглядають у кутові справи. Я хотів би додати просту відповідь, яка може бути щоденною у використанні ... де ви здебільшого потрапляєте до тих кутових справ (як, наприклад, уникнувши коми чи коми в лапках тощо).
FS (Field Separator) - це змінна, значення якої задано пробілом. Тож awk за замовчуванням розпадається на простір для будь-якого рядка.
Таким чином, використовуючи BEGIN (Виконати перед тим, як взяти ввід), ми можемо встановити це поле на все, що завгодно ...
awk 'BEGIN {FS = ","}; {print $3}'
Вищевказаний код надрукує 3-й стовпчик у файлі csv.
Інші відповіді працюють добре, але оскільки ви попросили рішення, використовуючи лише bash shell, ви можете зробити це:
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", і надіслати його в розділ "зробити" нашого циклу while
do echo "${csv_line[0]}";done < file
- зараз ми перебуваємо у фазі "робити", і ми говоримо відлуння 0-го елемента масиву "csv_line". Ця дія повторюється в кожному рядку файлу. < file
Частина просто говорить той час циклу , де читати. ПРИМІТКА: пам'ятайте, що в bash масиви індексуються 0, тому перший стовпець є 0-м елементом.
Отож, у вас це є, витягуючи стовпчик з CSV в оболонці. Інші рішення, ймовірно, більш практичні, але це чистий баш.
Ви можете використовувати GNU Awk, дивіться цю статтю в посібнику користувача . Як покращення рішення, представленого в статті (у червні 2015 року), наступна команда gawk дозволяє подвоїти лапки всередині подвійних котируваних полів; подвійна цитата позначена двома послідовними подвійними лапками ("") там. Крім того, це дозволяє пусті поля, але навіть це не може обробляти багаторядкові поля . Наступний приклад друкує 3-й стовпець (через 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 як розрив рядків, див. Вікіпедія .
Якщо вхід може містити багаторядкові поля, ви можете використовувати наступний скрипт. Зверніть увагу на використання спеціального рядка для розділення записів у висновку (оскільки новий рядок роздільника за замовчуванням може виникнути в межах запису). Знову наступний приклад друкує 3-й стовпець (через 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
може використовуватися для обробки довільних великих файлів.
Ось приклад файлу 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
Щоб отримати лише другий стовпець:
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 ...]
Мені потрібен був правильний розбір CSV, а не cut
/ awk
і молитва. Я пробую це на Mac без цього csvtool
, але маки йдуть з рубіном, тож ви можете:
echo "require 'csv'; CSV.read('new.csv').each {|data| puts data[34]}" | ruby
Спочатку ми створимо базовий CSV
[dumb@one pts]$ cat > file
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
Потім отримуємо 1-й стовпчик
[dumb@one pts]$ awk -F , '{print $1}' file
a
1
a
1
Я думаю, що найпростіше використовувати csvkit :
Отримує 2-й стовпець:
csvcut -c 2 file.csv
Однак, є також і csvtool , і, мабуть, ряд інших інструментів 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'
Цікаво, чому жодна з відповідей поки що не згадує csvkit.
csvkit - це набір інструментів командного рядка для перетворення та роботи з CSV
Я використовую його виключно для управління даними csv, і поки що я не знайшов проблеми, яку не міг би вирішити за допомогою cvskit.
Для витягування одного або декількох стовпців із файлу резюме можна скористатись 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
.
Ви не можете зробити це без повного аналізатора CSV.
cut
рахує?
Користуючись цим кодом деякий час, він не є "швидким", якщо не рахувати "вирізання та вставлення з stackoverflow".
Він використовує операторів $ {##} та $ {%%} у циклі замість IFS. Він називає 'err' і 'die', і підтримує лише коми, тире та трубу як символи SEP (це все, що мені потрібно).
err() { echo "${0##*/}: Error:" "$@" >&2; }
die() { err "$@"; 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
Ви також можете використовувати цикл while
IFS=,
while read name val; do
echo "............................"
echo Name: "$name"
done<itemlst.csv
echo '1,"2,3,4,5",6' | awk -F "\"*,\"*" '{print $2}'
буде надруковано2
замість2,3,4,5
.