Разделить файл CSV на более мелкие файлы, когда в первом столбце найдено целое число

У меня есть CSV-файл, который выглядит следующим образом:

1,'someval','otherval',,,,,
'','someotherval','some_otherval',,,,,
1BSD,'',,,,,
2,'val',,,,,
,,,,,,
2BSD,,,,,,
2BCD,,,,,,

Теперь я хочу разбить файл, когда первый столбец новой строки является целочисленным значением.

Итак, тогда для вышеуказанного ввода CSV < Я должен получить 2 новых файла с содержанием:

1,'someval','otherval',,,,,
,'someotherval','some_otherval',,,,,
1BSD,'val',,,,,

и

2,'val',,,,,
,,,,,,
2BSD,,,,,,
2BCD,,,,,,

соответственно.

Как я могу сделать это, используя Bash и / или Python? Благодаря.

2
задан 4 January 2018 в 16:13

2 ответа

Вы можете использовать утилиту csplit для разбиения регулярного выражения, например,

.
csplit -z file.csv '/^[0-9]\+,/' '{*}'
80
42

(значения показывают количество символов, выводимых в каждый файл - вы можете подавить их, добавив опцию -s).

Выходные файлы по умолчанию называются xx00, xx01 и т. Д. - при желании можно изменить префикс и суффикс.

Пример.

$ csplit -z file.csv '/^[0-9]\+,/' '{*}'
80
42
$ head xx*
==> xx00 <==
1,'someval','otherval',,,,,
'','someotherval','some_otherval',,,,,
1BSD,'',,,,,

==> xx01 <==
2,'val',,,,,
,,,,,,
2BSD,,,,,,
2BCD,,,,,,
3
ответ дан 4 January 2018 в 16:13
  • 1
    Снова спасибо за помощь мне, вывод команды locele как arvind@arvind-laptop:~ LANG=en_IN LANGUAGE=en_IN:en LC_CTYPE локали $ =" en_IN" LC_NUMERIC =" en_IN" LC_TIME =" en_IN" LC_COLLATE =" en_IN" LC_MONETARY =" en_IN" LC_MESSAGES=en_IN.UTF-8 LC_PAPER =" en_IN" LC_NAME =" en_IN" LC_ADDRESS =" en_IN" LC_TELEPHONE =" en_IN" LC_MEASUREMENT =" en_IN" LC_IDENTIFICATION =" en_IN" LC_ALL = – Arvind Gangwar 5 June 2012 в 08:31
  • 2
    Снова спасибо за помощь мне, вывод команды locele как arvind@arvind-laptop:~ LANG=en_IN LANGUAGE=en_IN:en LC_CTYPE локали $ =" en_IN" LC_NUMERIC =" en_IN" LC_TIME =" en_IN" LC_COLLATE =" en_IN" LC_MONETARY =" en_IN" LC_MESSAGES=en_IN.UTF-8 LC_PAPER =" en_IN" LC_NAME =" en_IN" LC_ADDRESS =" en_IN" LC_TELEPHONE =" en_IN" LC_MEASUREMENT =" en_IN" LC_IDENTIFICATION =" en_IN" LC_ALL = – Arvind Gangwar 5 June 2012 в 08:31
  • 3
    Снова спасибо за помощь мне, вывод команды locele как arvind@arvind-laptop:~ LANG=en_IN LANGUAGE=en_IN:en LC_CTYPE локали $ =" en_IN" LC_NUMERIC =" en_IN" LC_TIME =" en_IN" LC_COLLATE =" en_IN" LC_MONETARY =" en_IN" LC_MESSAGES=en_IN.UTF-8 LC_PAPER =" en_IN" LC_NAME =" en_IN" LC_ADDRESS =" en_IN" LC_TELEPHONE =" en_IN" LC_MEASUREMENT =" en_IN" LC_IDENTIFICATION =" en_IN" LC_ALL = – Arvind Gangwar 5 June 2012 в 08:31
  • 4
    Снова спасибо за помощь мне, вывод команды locele как arvind@arvind-laptop:~ LANG=en_IN LANGUAGE=en_IN:en LC_CTYPE локали $ =" en_IN" LC_NUMERIC =" en_IN" LC_TIME =" en_IN" LC_COLLATE =" en_IN" LC_MONETARY =" en_IN" LC_MESSAGES=en_IN.UTF-8 LC_PAPER =" en_IN" LC_NAME =" en_IN" LC_ADDRESS =" en_IN" LC_TELEPHONE =" en_IN" LC_MEASUREMENT =" en_IN" LC_IDENTIFICATION =" en_IN" LC_ALL = – Arvind Gangwar 5 June 2012 в 08:31
  • 5
    Снова спасибо за помощь мне, вывод команды locele как arvind@arvind-laptop:~ LANG=en_IN LANGUAGE=en_IN:en LC_CTYPE локали $ =" en_IN" LC_NUMERIC =" en_IN" LC_TIME =" en_IN" LC_COLLATE =" en_IN" LC_MONETARY =" en_IN" LC_MESSAGES=en_IN.UTF-8 LC_PAPER =" en_IN" LC_NAME =" en_IN" LC_ADDRESS =" en_IN" LC_TELEPHONE =" en_IN" LC_MEASUREMENT =" en_IN" LC_IDENTIFICATION =" en_IN" LC_ALL = – Arvind Gangwar 5 June 2012 в 08:31
  • 6
    Снова спасибо за помощь мне, вывод команды locele как arvind@arvind-laptop:~ LANG=en_IN LANGUAGE=en_IN:en LC_CTYPE локали $ =" en_IN" LC_NUMERIC =" en_IN" LC_TIME =" en_IN" LC_COLLATE =" en_IN" LC_MONETARY =" en_IN" LC_MESSAGES=en_IN.UTF-8 LC_PAPER =" en_IN" LC_NAME =" en_IN" LC_ADDRESS =" en_IN" LC_TELEPHONE =" en_IN" LC_MEASUREMENT =" en_IN" LC_IDENTIFICATION =" en_IN" LC_ALL = – Arvind Gangwar 5 June 2012 в 08:31

Я хотел посмотреть, как много из этого я смогу сделать с sed, и мне удалось сделать довольно многое из этого. Мы можем писать файлы с помощью sed, используя команды w и W, но я не мог придумать, как написать отдельный файл для каждой итерации цикла sed, поэтому мне пришлось использовать оболочку петля. sed, вероятно, не тот инструмент, который можно использовать для этой работы, и, вероятно, есть более хороший способ сделать это с sed. Во всяком случае, вот что я придумал:

#!/bin/bash
sed ':a;N;s/\n/\x00/; ta' input | sed -r 's/\x00([0-9]+(,|\x00|$))/\n\1/g' > edited
n=0
while [ -s edited ]; do 
    ((n++))
    sed -n '1p' edited > csv-"$n"
    sed -i '1d' edited
done
sed -i 'y/\x00/\n/' csv-*
rm edited

Комментарии

  • заменяют символы новой строки нулевым символом \x00, используя цикл sed. Это сделано для того, чтобы позже мы могли использовать переводы строк как значимые разделители.

    sed ':a;N;s/\n/\x00/; ta' input
    
  • передают результат и добавляют новые строки перед целыми числами, которые были в первом поле, и записывают результат в файл, edited

    | sed -r 's/\x00([0-9]+(,|\x00|$))/\n\1/g' > edited
    
  • инициализировать переменную для увеличения

    n=0
    
  • , пока edited не пусто, делать вещи

    while [ -s edited ]; do
    
  • инкремент n

    ((n++))
    
  • записать первую строку edited в новый файл csv-$n, где $n - текущее значение n

    sed -n '1p' edited > csv-"$n"
    
  • удалить первую строку из edited

    sed -i '1d' edited
    

    , это конец цикла, и поскольку у нас есть только одна строка для каждого файла, который мы хотим записать, это не так медленно, как обработка каждой строки исходного файла в цикле, но, тем не менее, это медленно!

  • для каждого файла, который мы создали, превратите нулевые символы обратно в символы новой строки

    sed -i 'y/\x00/\n/' csv-*
    
  • удалить промежуточный файл

    rm edited
    
2
ответ дан 4 January 2018 в 16:13

Другие вопросы по тегам:

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