Вопрос или проблема
У меня есть проблемы со скриптом, который анализирует .csv файл
Информация о .csv:
#1,13/8/2020,[email protected],[email protected],,Тема,"Дорогой друг,
Информация была обновлена. Пожалуйста, войдите в приложение, чтобы просмотреть до 30 августа 2020 года. Спасибо.
С наилучшими пожеланиями,
г-н Мак",В ожидании,13/8/2020 12:35
Вот как информация должна быть разделена:
MsgID,Дата,Кому,Копия,Скрытая Копия,Тема,Текст,Статус,Время записи
MsgID=#1
Дата=13/8/2020
[email protected]
[email protected]
Скрытая Копия=
Тема=Тема
Текст=Дорогой друг,
Информация была обновлена. Пожалуйста, войдите в приложение, чтобы просмотреть до 30 августа 2020 года. Спасибо.
С наилучшими пожеланиями,
г-н Мак
Статус=В ожидании
Время записи=13/8/2020 12:35
Проблемы, с которыми я сталкиваюсь, связаны с текстом тела по двум причинам: запятая “,” в тексте, которая ломает скрипт, и другая причина – переносы строк в тексте.
Вот скрипт, который я делал:
#!/bin/bash
export TIMESTAMP="$( date '+%d/%m/%Y %H:%M:%S' )"
INPUT=/tmp/test.csv
OUTPUT=/tmp/test.csv.out
OLDIFS=$IFS
IFS=','
[ ! -f $INPUT ] && { echo "$INPUT файл не найден"; exit 99; }
while read msgid dat to cc bcc subject body status timesta
do
echo "MSG ID : $msgid"
echo "Дата : $dat"
echo "Кому : $to"
echo "Копия : $cc"
echo "Скрытая Копия : $bcc"
echo "Тема : $subject"
echo "Текст : $body"
echo "Статус : $status"
echo "Время записи : $timesta"
echo $body | mail -s "$subject" $to -c $cc -b $bcc
printf "$msgid,$dat,$to,$cc,$bcc,$subject,$body,Отправлено,$TIMESTAMP" >> $OUTPUT
done < $INPUT
IFS=$OLDIFS
Оболочка – это просто очень плохой инструмент для анализа текста. Вы должны использовать его только для самых простых задач, и, вероятно, даже в этом случае не стоит. Это медленно, неэффективно, его очень сложный синтаксис делает его подверженным ошибкам, и ему не хватает самых основных инструментов обработки текста. К тому же, CSV – это сложный формат, который позволяет использовать вложенные и многострочные записи. Попытка проанализировать файл CSV в оболочке просто приведет к проблемам.
Поэтому используйте для этого соответствующий язык программирования с поддержкой анализа CSV. Например, на Python:
#!/bin/python3
import csv
import sys
with open(sys.argv[1], newline="") as csvfile:
fieldnames = ("MsgID","Дата","Кому","Копия","Скрытая Копия",
"Тема","Текст","Статус","Время записи")
reader = csv.reader(csvfile, delimiter=",")
for row in reader:
for fieldName, value in zip(fieldnames,row):
print("%s: %s" % (fieldName,value))
Я сохранил вышеуказанный скрипт как foo.py
, а затем:
MsgID: #1
Дата: 13/8/2020
Кому: [email protected]
Копия: [email protected]
Скрытая Копия:
Тема: Тема
Текст: Дорогой друг,
Информация была обновлена. Пожалуйста, войдите в приложение, чтобы просмотреть до 30 августа 2020 года. Спасибо.
С наилучшими пожеланиями,
г-н Мак
Статус: В ожидании
Время записи: 13/8/2020 12:35
Как вы можете видеть, он правильно распознал все поля. Таким образом, чтобы также отправить почту, вы можете сделать что-то подобное (адаптировано отсюда):
#!/bin/python3
import csv
import sys
import subprocess
import os
def send_message(to, cc, bcc, subject, body):
try:
process = subprocess.Popen(['mail', '-s', subject, '-c', cc, '-b', bcc, to],
stdin=subprocess.PIPE)
except Exception as error:
print(error)
process.communicate(body)
with open(sys.argv[1], newline="") as csvfile:
reader = csv.reader(csvfile, delimiter=",")
for row in reader:
(msgID, date, to, cc, bcc, subj, body, status, timestamp) = row
send_message(to, cc, bcc, subj, body)
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Вы, кажется, используете BSD mail
на основе предоставленных вами параметров. У меня нет доступа к рабочей системе с установленным этим инструментом, поэтому я не смог протестировать приведенный выше скрипт для отправки почты. Тем не менее, он должен хотя бы служить хорошим началом.
Вы можете использовать инструмент Miller (https://github.com/johnkerl/miller), специализированный для работы с структурированными текстовыми данными.
Например, начиная с этого файла input.txt
#1,13/8/2020,[email protected],[email protected],,Тема,"Дорогой друг,
Информация была обновлена. Пожалуйста, войдите в приложение, чтобы просмотреть до 30 августа 2020 года. Спасибо.
С наилучшими пожеланиями,
г-н Мак",В ожидании,13/8/2020 12:35
и запустив
mlr --implicit-csv-header --c2x cat then label MsgID,Дата,Кому,Копия,Скрытая Копия,Тема,Текст,Статус,Время записи input.txt
вы получите
MsgID #1
Дата 13/8/2020
Кому [email protected]
Копия [email protected]
Скрытая Копия
Тема Тема
Текст Дорогой друг,
Информация была обновлена. Пожалуйста, войдите в приложение, чтобы просмотреть до 30 августа 2020 года. Спасибо.
С наилучшими пожеланиями,
г-н Мак
Статус В ожидании
Время записи 13/8/2020 12:35
Если вы хотите удалить переносы строк из поля текста, вы можете запустить
mlr --implicit-csv-header --c2x cat then label MsgID,Дата,Кому,Копия,Скрытая Копия,Тема,Текст,Статус,Время записи then put '$Текст=gsub($Текст,"\n"," ")' input.txt
чтобы получить
MsgID #1
Дата 13/8/2020
Кому [email protected]
Копия [email protected]
Скрытая Копия
Тема Тема
Текст Дорогой друг, Информация была обновлена. Пожалуйста, войдите в приложение, чтобы просмотреть до 30 августа 2020 года. Спасибо. С наилучшими пожеланиями, г-н Мак
Статус В ожидании
Время записи 13/8/2020 12:35
Ответ или решение
Извлечение информации в кавычках из .csv файла
Введение
При работе с .csv файлами в сценариях на bash могут возникать затруднения, особенно когда необходимо корректно извлечь данные, заключенные в кавычки, и обработать их с учетом особенностей формата .csv. Особенно это актуально для текста, содержащего запятые и переносы строк, что может нарушить ожидаемую структуру данных.
Описание проблемы
В представленном примере .csv файла информация разбивается на следующие поля: MsgID, Date, To, CC, BCC, Subject, Body, Status, Timestamp
. Однако текст сообщения, находящийся в поле Body, содержит как запятые, так и переносы строк. Это приводит к некорректной работе скрипта, который использует bash для обработки файла.
Пример .csv файла:
#1,13/8/2020,[email protected],[email protected],,Subject,"Dear Dude,
Information have been updated. Please login to APP to review by 30th August 2020. Thank you.
Best regards,
Mr. Mack",Pending,13/8/2020 12:35
Предложение решения
Для избегания проблем с разбором текста в CSV форматах, рекомендуется использовать языки программирования, которые поддерживают парсинг CSV «из коробки», такие как Python.
Пример на Python
Если у вас установлен Python, вы можете воспользоваться следующим сценарием для корректного извлечения всех полей из .csv:
#!/bin/python3
import csv
import sys
import subprocess
def send_message(to, cc, bcc, subject, body):
try:
process = subprocess.Popen(['mail', '-s', subject, '-c', cc, '-b', bcc, to], stdin=subprocess.PIPE)
process.communicate(body.encode())
except Exception as error:
print(error)
if __name__ == "__main__":
with open(sys.argv[1], newline="") as csvfile:
reader = csv.reader(csvfile, delimiter=",")
for row in reader:
(msgID, date, to, cc, bcc, subj, body, status, timestamp) = row
print(f"MsgID: {msgID}\nDate: {date}\nTo: {to}\nCC: {cc}\nBCC: {bcc}\nSubject: {subj}\nBody: {body}\nStatus: {status}\nTimestamp: {timestamp}")
send_message(to, cc, bcc, subj, body)
Пояснение к коду
- Импорт библиотек: Импортируем необходимые модули для работы с CSV и отправки почты.
- Функция send_message: Запускает команду отправки почты с правильными параметрами.
- Чтение .csv файла: Используется
csv.reader
, чтобы правильно обрабатывать текст с учетом кавычек, запятых и переносов строк.
Альтернативное решение: Использование Miller
Еще одним подходом является использование утилиты Miller, которая оптимизирована для работы со структурированными текстовыми данными. Запуск следующей команды позволит извлечь и вывести нужную информацию:
mlr --implicit-csv-header --c2x cat then label MsgID,Date,To,CC,BCC,Subject,Body,Status,Timestamp input.txt
При этом возможно также убрать переносы строк из текста поля Body:
mlr --implicit-csv-header --c2x cat then label MsgID,Date,To,CC,BCC,Subject,Body,Status,Timestamp then put '$Body=gsub($Body,"\n"," ")' input.txt
Заключение
Выбор правильного инструмента для обработки данных .csv в значительной степени определяет успех итогового результата. Для обработки данных, содержащих сложные текстовые элементы, рекомендуется использовать языки программирования с функциями для работы с CSV, такие как Python, или специализированные инструменты, такие как Miller. Эти подходы помогут избежать распространенных ошибок и упростят работу с текстом, содержащим запятые и переносы строк.