Использование sed для замены символа, но не в том случае, если он находится в строке в CSV-файле bash

Доброе утро всем, У меня есть CSV-файл, и я хочу заменить все разделители «,» на разделитель «;», но мне нужно сохранить «,», если он находится в строке (в поле CSV):

Текущий CSV-файл

"001","User,Super","04/04/2024"

Ожидаемый CSV-файл

"001";"User,Super";"04/04/2024"

Есть ли способ исключить проверку, если она находится между строкой? Я хотел бы сделать это в bash с помощью пары команд без необходимости написания специального цикла для проверки каждого символа и позиции.

Я попробовал следующую команду, но безуспешно:

sed -r 's/("*,*")|,/\;/g' test.csv

Люди здесь делают упрощающие предположения, потому что без них обработка CSV с использованием подобных sed является общеизвестно неприятной проблемой. Достаточно известно, что в руководстве gawk ​​есть раздел о том, как правильно обрабатывать CSV-файлы. Поэтому я предлагаю вам просто использовать это.

Verpous 04.04.2024 15:51

Обработка общих файлов CSV на удивление сложна. См. Как разобрать CSV в скрипте Bash? несколько хороших способов (и некоторых плохих, будьте осторожны) это сделать. Например, csvtool -u ';' ... будет делать то, что вы хотите, на 100% надежно для любого файла CSV.

pjh 04.04.2024 16:08

Я нашел очень изящный способ сделать это с помощью awk, спасибо всем!

Lorenzo Cesana 04.04.2024 17:56
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
71
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Предположения:

  • все поля заключены в двойные кавычки
  • двойные кавычки не отображаются как фактические данные
  • между двойными кавычками и запятой (разделителем) нет пробелов.

ПРИМЕЧАНИЕ. Если эти предположения неверны, ОП необходимо будет обновить вопрос, добавив более реалистичный набор выборочных данных.

Простая 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, так как это дает мне больше гибкости при последующем анализе, но эта команда выполняет свою работу. Еще раз спасибо всем!

Lorenzo Cesana 05.04.2024 16:52

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