Доброе утро всем, У меня есть CSV-файл, и я хочу заменить все разделители «,» на разделитель «;», но мне нужно сохранить «,», если он находится в строке (в поле CSV):
Текущий CSV-файл
"001","User,Super","04/04/2024"
Ожидаемый CSV-файл
"001";"User,Super";"04/04/2024"
Есть ли способ исключить проверку, если она находится между строкой? Я хотел бы сделать это в bash с помощью пары команд без необходимости написания специального цикла для проверки каждого символа и позиции.
Я попробовал следующую команду, но безуспешно:
sed -r 's/("*,*")|,/\;/g' test.csv
Обработка общих файлов CSV на удивление сложна. См. Как разобрать CSV в скрипте Bash? несколько хороших способов (и некоторых плохих, будьте осторожны) это сделать. Например, csvtool -u ';' ...
будет делать то, что вы хотите, на 100% надежно для любого файла CSV.
Я нашел очень изящный способ сделать это с помощью awk, спасибо всем!
Предположения:
ПРИМЕЧАНИЕ. Если эти предположения неверны, ОП необходимо будет обновить вопрос, добавив более реалистичный набор выборочных данных.
Простая sed
идея:
$ sed 's/","/";"/g' test.csv
"001";"User,Super";"04/04/2024"
Вы можете использовать инструмент, который понимает CSV, например xsv:
$ xsv fmt -t ';' --quote-always <<< '"001","User,Super","04/04/2024"'
"001";"User,Super";"04/04/2024"
Поскольку обработка формата CSV на удивление сложна, лучший способ выполнить подобную задачу — использовать проверенный инструмент, предназначенный для обработки файлов CSV. Один из таких инструментов, модуль csv
, входит в стандартную комплектацию Python. Этот Shellcheck-чистый код Bash демонстрирует один из способов использования модуля Python для обработки данных CSV как части программы Bash:
#! /bin/bash -p
csv='"001","User,Super","04/04/2024"'
python_code='
import csv,sys
r = csv.reader(sys.stdin, delimiter = ",")
w = csv.writer(sys.stdout, delimiter = ";", quoting=csv.QUOTE_ALL)
w.writerows(r)
'
python -c "${python_code// /}" <<<"$csv"
Эта программа выводит:
"001";"User,Super";"04/04/2024"
"${python_code// /}"
расширяется до содержимого python_code
с удаленным отступом (который используется для удобства чтения). Если отступ не удален, команда Python завершается с ошибкой IndentationError: unexpected indent
. См. Замена части строки (BashFAQ/100 (Как манипулировать строками в bash?)) для объяснения ${var//old/new}
.quoting=csv.QUOTE_ALL
используется для того, чтобы гарантировать, что все поля CSV в выходных данных заключены в кавычки. Без этого вывод программы станет 001;User,Super;04/04/2024
. Это действительный CSV (кавычки излишни), но я предполагаю, что вы все равно захотите их сохранить.Это может сработать для вас (GNU sed):
sed -E ':a;s/^(("[^,"]*",)*"[^,"]*),/\1\n/;ta;y/\n,/,;/' file
Выполните итерацию по строке, заменяя все запятые в двойных кавычках символами новой строки.
Когда замен больше нет, преобразуйте символы новой строки в запятые, а запятые в точки с запятой.
Я выбрал использование gawk, так как это дает мне больше гибкости при последующем анализе, но эта команда выполняет свою работу. Еще раз спасибо всем!
Люди здесь делают упрощающие предположения, потому что без них обработка CSV с использованием подобных
sed
является общеизвестно неприятной проблемой. Достаточно известно, что в руководстве gawk есть раздел о том, как правильно обрабатывать CSV-файлы. Поэтому я предлагаю вам просто использовать это.