Выключите машину и получите замещающий диск теперь! Поврежденные секторы в жестких дисках имеют тенденцию расти экспоненциально, крупная потеря данных неизбежна.
ОБНОВЛЕНИЕ:
На самом деле намного более легкий путь состоит в том, чтобы установить разделитель записей в 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"
Я рекомендовал бы использовать проверенный в бою модуль парсинга 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
если это - стиль 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 и сбросило количество, когда последнее поле достигнуто.
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
Самый простой способ сделать это - использовать csvtool . У меня были и другие варианты использования csvtool, и он может соответствующим образом обрабатывать кавычки или разделители, если они появляются в самих данных столбца.
csvtool format '%(4)\n' input.csv
Замена 4 номером столбца эффективно извлечет данные столбца, которые вы ищете.
Получите 4-й элемент вашего CSV с помощью.
cut -d , -f 4 myFile.csv
Сохраните его в файл с помощью:
cut -d , -f 4 myFile.csv | cat >> my4thEltsFile.csv
"1","text1","<p>bi
нет1,"text1","<p>bi
. Это решение все еще работает? – agstudy 20.12.2013, 17:20"
. Я пишу объяснение того, как эта вещь работы, обновит через несколько минут. – terdon♦ 20.12.2013, 17:22gawk
. – terdon♦ 20.12.2013, 17:43