Как извлечь столбцы из файла CSV, обработать и создать файл CSV на основе результата извлечения и обработки?

Это фрагмент исходного CSV-файла.

%status,date,job,project,start,end,description
%
//,18.03.2021,sib,sib-dede,07:00,15:00,dede-mongo
%
//,11.06.2021,sib,sib-dede,07:00,15:00,dede-mongo
%
//,24.06.2021,sib,sib-dede,07:00,15:00,dede-mongo
%
?,02.08.2021,sib,sib-accounting,14:35,16:35,business-plan
%
?,13.10.2021,sb,sb-accounting,11:30,12:00,e-mail-pump

Мне нравится извлекать из исходного CSV-файла время начала в столбце 5 и время окончания в столбце 6.

Далее, в зависимости от времени начала и окончания, я предпочитаю рассчитывать продолжительность в часах или минутах (не обращайте внимания).

В конце концов, мне нравится брать исходный файл CSV, вставлять новый столбец между существующими столбцами 6 и 7 с обработанной длительностью и сохранять это добавление в результирующем файле CSV.

Есть ли у кого-нибудь идеи, как решить эту проблему в командной строке GNU Debian Linux?

Я знаю, что могу cut определённые столбцы из файла CSV вот так.

cut -d, -f5,6 < ./source.csv > ./result.csv

Однако мне все еще не хватает обработки длительности и создания результирующего файла CVS.

PS: Я отдаю предпочтение Bash.

PPS: Есть связанные вопросы, такие как этот, но я не нашел ни одного близкого к этому вопросу.

Между ними действительно есть эти странные % строчки?

Armali 03.09.2024 11:17

Да, эти странные % строки действительно находятся между ними.

dancesWithCycles 03.09.2024 11:23

Я удалил странные % строки типа вот это.

dancesWithCycles 03.09.2024 11:34

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

markp-fuso 03.09.2024 14:19

Я подозреваю, что эти «странные строки» на самом деле представляют собой какой-то управляющий символ в вашем столбце %status, который вы делаете, чтобы выглядеть как строки, в которых всего лишь %, за которыми следуют строки, начинающиеся с % или //, хотя на самом деле это просто %<control char>// или что-то подобное. строка в начале каждой строки. Вам действительно следует это понять, чтобы получить надежное решение, которое сможет правильно обрабатывать эти поля как есть.

Ed Morton 03.09.2024 15:08
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
57
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я отдаю предпочтение Bash

Но вы можете сделать все это за один раз, например. используя mktime из GNU Awk (при условии, что знаки % (или последующие символы новой строки) в вашем образце являются просто опечаткой и что время в столбце 6 больше, чем время в столбце 5, в противном случае результат будет отрицательным):

awk -F , -v OFS=, '{
  $8=$7; $7=(
    mktime(sprintf("0 0 0 %d %d 0", substr($6,1,2), substr($6,4,2))) - 
    mktime(sprintf("0 0 0 %d %d 0", substr($5,1,2), substr($5,4,2)))
  ) / 60; print
}' source.csv

Ваше здоровье! Я удалил странные строки %, такие как это. Однако расчет продолжительности еще не завершен. Для продолжительности менее часа этот ответ округляется до следующего полного часа в большую или меньшую сторону.

dancesWithCycles 03.09.2024 11:36

Сначала я думал, что нужно заменить substr($6,3,2) на substr($6,3,4) и так далее, но оказалось, что этого недостаточно.

dancesWithCycles 03.09.2024 11:44

Теперь я понял! Вам нужно заменить substr($6,3,2) на substr($6,4,2) и substr($5,3,2) на substr($5,4,2). Не могли бы вы изменить свой ответ, чтобы я мог отметить его как решение?

dancesWithCycles 03.09.2024 11:55

@dancesWithCycles Да, извините за опечатку, спасибо, что заметили! substr("14:35",3,2) произвел бы :3, но нам нужно substr("14:35",4,2), чтобы получить 35.

pmf 03.09.2024 12:13

Предполагая, что:

  1. Все временные метки относятся к одному и тому же дню, поскольку у вас нет никаких указаний на дату во входных данных, и поэтому нет надежного способа обработки продолжительности, которая может превышать 24 часа.
  2. Временные метки представляют собой стандартное время, поэтому нет необходимости в изменении часа для перехода на летнее время.
  3. У вас действительно есть строки, состоящие всего из %, за которыми следуют строки, начинающиеся с // или ? во входных данных, и
  4. Вы также хотите, чтобы строка заголовка была изменена и включала заголовок, например diff, для добавляемого столбца.

затем используя любой awk:

$ awk '
    BEGIN { FS=OFS = "," }
    NF > 1 {
        if ( NR == 1 ) {
            diff = "diff"
        }
        else {
            split($5, b, ":")
            split($6, e, ":")
            beg = b[1]*60 + b[2]
            end = e[1]*60 + e[2]
            diff = end - beg
        }
        $6 = $6 OFS diff
        print
    }
' file
%status,date,job,project,start,end,diff,description
//,18.03.2021,sib,sib-dede,07:00,15:00,480,dede-mongo
//,11.06.2021,sib,sib-dede,07:00,15:00,480,dede-mongo
//,24.06.2021,sib,sib-dede,07:00,15:00,480,dede-mongo
?,02.08.2021,sib,sib-accounting,14:35,16:35,120,business-plan
?,13.10.2021,sb,sb-accounting,11:30,12:00,30,e-mail-pump

Не нужно сначала запускать grep — передача grep в awk является антипаттерном, см. https://porkmail.org/era/unix/award#grep.

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

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

Скрипт Bash, который принимает несколько аргументов пути и проверяет, можно ли там успешно создать файлы
Почему bash не завершает выполнение сценария после ошибки внутри скобок?
Как запустить эмулятор терминала во время работы оболочки?
Как мне отслеживать и уничтожать все процессы, порожденные запуском сценария, не зная имен подпроцессов?
Bash: медленнее использовать zcat по сравнению с cat+zcat или cat+pv+zcat
Как передать переменную оболочки, возвращаемую из Pythonscript, в другую оболочку для запуска другого Pythonscript в правиле Makefile?
Правильное использование кавычек при подстановке команд – как?
Синтаксическая ошибка рядом с токеном в сценарии bash, инициализирующем conda
Удалите вывод ansi escape из файла журнала с помощью cat/ansifilter или любых других инструментов
Почему локальной переменной не присваивается нелокальная переменная с тем же именем?