извлеките 4-й столбец из файла CSV с помощью команды Unix

Выключите машину и получите замещающий диск теперь! Поврежденные секторы в жестких дисках имеют тенденцию расти экспоненциально, крупная потеря данных неизбежна.

6
20.12.2013, 17:59
7 ответов

ОБНОВЛЕНИЕ:

На самом деле намного более легкий путь состоит в том, чтобы установить разделитель записей в gawk:

$ gawk 'BEGIN{RS="\"\n"; FS=","}{print $4}' myFile.csv
"col4
"4th column
"4th column2

Однако это удалит запаздывание " от конца каждого столбца. Для фиксации этого, можно распечатать его сами:

$ gawk 'BEGIN{RS="\"\n"; FS=","}{print $4"\""}' myFile.csv
"col4"
"4th column"
"4th column2"

Если Вы не хотите кавычки вообще, можно установить разделителя полей на ",":

$ gawk 'BEGIN{RS="\"\n"; FS="\",\""}{print $3}' myFile.csv
col3
4th column
4th column2

Единственным путем я могу думать об Одном способе сделать, это должно сначала изменить файл и затем проанализировать его. В Вашем примере новая строка, которая на самом деле разделяет две записи, всегда следует за a ":

"col1","col2","col3","col4"   <-- here 
1,"text1","<p>big             <-- no "

Если это так, для всего файла, можно заменить все новые строки, которые сразу не являются после a " с заполнителем и тем самым имеют все в одной строке. Можно затем обычно анализировать с gawk и наконец замените заполнителя новой строкой снова. Я буду использовать строку &%& как заполнитель, так как это вряд ли будет существовать в Вашем файле:

$ perl -pe 's/"\s*\n/"&%&/; s/\n//g; s/&%&/\n/;' myFile.csv | awk -F, '{print $4}'
"col4"
"4th column"
"4th column2"

-p флаг для perl средства print each line of the input file после применения сценария, данного -e. Затем существует 3 замены (s/foo/bar/) команды:

  • s/"\s*\n/"&%&/ : Это найдет любого " который сопровождается 0 или больше пробельными символами (\s*) и затем символ новой строки (\n). Это заменит это "&%&. Кавычки добавляются для сохранения формата и &%& просто случайный заполнитель, это могло быть что-либо, что не появляется в Вашем файле.

  • s/\n//g; : так как реальные новые строки были заменены заполнителем, мы можем теперь безопасно удалить все остающиеся новые строки в этой записи. Это означает, что все строки текущей записи были теперь связаны в текущую строку.

  • s/&%&/\n/ : Это возвращает заполнителя в нормальную новую строку.

Для понимания вывода команды выполняет его без gawk:

$ perl -pe 's/"\s*\n/"&%&/; s/\n//g; s/&%&/\n/;' myFile.csv 
"col1","col2","col3","col4"
1,"text1","<p>big      html     text</p>","4th column"
2,"text2","<p>big2      html2     text2</p>","4th column2"

Так, у Вас теперь есть свои длинные записи на одних строках, и это - идеальная еда для gawk.

Можно также сделать это непосредственно в Perl:

perl -ne '$/="\"\n"; chomp;@a=split(/,/);print "$a[3]\"\n"' myFile.csv
"col4"
"4th column"
"4th column2"

Это использует немного больше волшебства Perl. $/специальная переменная является входным разделителем записей. Путем установки его на "\n мы говорим Perl разделять строки не в \n но только в "\n" так, чтобы каждую запись рассматривали как одну строку. После того как это сделано, chomp удаляет новую строку из конца строки (для печати позже) и split разделения каждая запись (на ,) и сохраняет его в массиве @a. Наконец, мы печатаем 4-й элемент массива (массивы пронумерованы от 0 так, чтобы был $a[3]) который является 4-м столбцом.

И еще больше волшебства, включите автоматическое плевание (-a) и разделенный на запятых (F","). Это разделит каждую запись на специальное предложение @F массив и Вы можете распечатать 4-й элемент массива:

$ perl -F"," -ane '$/="\"\n";chomp;print "$F[3]"' myFile.csv
"col4"
"4th column"
"4th column2"
10
27.01.2020, 20:20
  • 1
    Спасибо за Ваш ответ.Мне очень жаль. Я отредактировал свой вопрос и если Вы отмечаете, что я имею "1","text1","<p>bi нет 1,"text1","<p>bi. Это решение все еще работает? –  agstudy 20.12.2013, 17:20
  • 2
    @agstudy да, пока новая строка в конце строки все еще сразу после a ". Я пишу объяснение того, как эта вещь работы, обновит через несколько минут. –  terdon♦ 20.12.2013, 17:22
  • 3
    @agstudy видит обновленный ответ для (намного) более простого способа использовать gawk. –  terdon♦ 20.12.2013, 17:43

Я рекомендовал бы использовать проверенный в бою модуль парсинга CSV. Например:

perl -MText::CSV -E '
    $csv = Text::CSV->new({binary=>1}); 
    while ($row = $csv->getline(STDIN)) {say $row->[3]}
' < file.csv
col4
4th column
4th column2

или это приводит к тем же результатам:

ruby -rcsv -e 'CSV.foreach(ARGV.shift) {|row| puts row[3]}' file.csv
6
27.01.2020, 20:20
  • 1
    я должен установить что-то для получения MText? –  agstudy 20.12.2013, 17:34
  • 2
    Вы должны cpan install Text::CSV –  glenn jackman 20.12.2013, 17:35
  • 3
    я нахожусь под окнами. cpan не работают. Но спасибо за Ваш ответ. (+ 1) –  agstudy 20.12.2013, 17:38
  • 4
    Какое распределение Perl Вы используете в окнах? Должен быть, что-то для установки новых модулей –  glenn jackman 20.12.2013, 17:43
  • 5
    я имею v5.8.8 built for msys –  agstudy 20.12.2013, 17:47

если это - стиль Unix "\n" законченные строки

tr -d "\n" < myfile.csv | awk 'BEGIN{RS=","} !(NR % 4)'

Некоторые поля являются мультилиниями tr -d "\n"удаляет весь символ новых строк, создавая поток"", отделились значения. awk говорят использовать"", как разделитель строки и распечатать каждый раз (номер строки по модулю 4) 0.

Это только работает, если 4-е поле является последним полем (как в Вашем образце). Если это не так:

tr -d "\n" < myfile.csv | awk 'BEGIN{RS=","; last=12} (++c == 4) (c == last) {c=0}'

Это считает строки, печатает строку, когда количество равняется 4 и сбросило количество, когда последнее поле достигнуто.

2
27.01.2020, 20:20
  • 1
    +1! можно ли объяснить немного команды здесь. файл –  agstudy 20.12.2013, 18:19
  • 2
    @agstudy при редактировании и упрощении сценария, я добавил ошибку (забыл"!" в awk). –  Emmanuel 20.12.2013, 18:30

Python:

python -c "import csv,sys; print '\n'.join([ r[3] for r in csv.reader(open(sys.argv[1]))])" myfile.csv

Консервативное памятью решение для больших файлов, которое выполняет итерации через файл строки за один раз в отличие от вышеупомянутого подхода, который загружает содержание файла в память с помощью списка

#!/usr/bin/env python
import sys
import csv
with open(sys.argv[1]) as f:
  for row in csv.reader(f):
    print(row[3])

РЕЗУЛЬТАТ ИСПЫТАНИЙ всех Решений:

ОС: Ubuntu 12.04

Общедоступная загрузка данных CSV с: http://seanlahman.com/baseball-archive/statistics/

Детали версий

root@ubuntu:~# python --version
Python 2.7.3
root@ubuntu:~# ruby --version
ruby 1.8.7 (2011-06-30 patchlevel 352) [i686-linux]
root@ubuntu:~# perl --version

This is perl 5, version 14, subversion 2 (v5.14.2) built for i686-linux-gnu-thread-multi-64int

Результат с time

root@ubuntu:~# time python -c "import csv,sys; print '\n'.join([ r[3] for r in csv.reader(open(sys.argv[1]))])" Master.csv > /tmp/python

real    0m1.112s
user    0m0.056s
sys     0m0.316s
root@ubuntu:~# time ruby -rcsv -e 'CSV.foreach(ARGV.shift) {|row| puts row[3]}' Master.csv > /tmp/ruby

real    0m24.582s
user    0m23.397s
sys     0m0.448s
root@ubuntu:~# time perl -MText::CSV -E '
>     $csv = Text::CSV->new({binary=>1});
>     while ($row = $csv->getline(STDIN)) {say $row->[3]}
> ' < Master.csv > /tmp/perl

real    0m7.049s
user    0m5.876s
sys     0m0.468s
5
27.01.2020, 20:20
  • 1
    делает это решение, эффективно? –  agstudy 20.12.2013, 18:19
  • 2
    как XML, CSV должен быть синтаксическим анализом с помощью языков как Python, Perl, Ruby.. –  Rahul Patil 20.12.2013, 18:26
  • 3
    я - разработчик R/python. Таким образом, Если я должен получить серьезное основание спросить об эффективности здесь, не так ли? Также здесь у нас есть некоторые хорошие решения с помощью команды Unix. –  agstudy 20.12.2013, 18:28
  • 4
    Жаль сэр, у меня нет хорошего ответа. –  Rahul Patil 20.12.2013, 18:31
  • 5
    :) продвигается! у Вас уже есть Python хороший ответ (я upvote). Я просто спрашиваю, эффективны ли Вы решение для контакта с файлом на 2 ГБ. (лично я предпочитаю использовать Python также, но здесь не так эффективно, как я хочу). –  agstudy 20.12.2013, 18:36

Попробуйте следующее:[12117]

1
27.01.2020, 20:20

Самый простой способ сделать это - использовать csvtool . У меня были и другие варианты использования csvtool, и он может соответствующим образом обрабатывать кавычки или разделители, если они появляются в самих данных столбца.

csvtool format '%(4)\n' input.csv

Замена 4 номером столбца эффективно извлечет данные столбца, которые вы ищете.

1
27.01.2020, 20:20

Получите 4-й элемент вашего CSV с помощью.

cut -d , -f 4 myFile.csv  

Сохраните его в файл с помощью:

cut -d , -f 4 myFile.csv | cat >> my4thEltsFile.csv
0
27.01.2020, 20:20

Теги

Похожие вопросы