2

редактировать: теперь, когда я получил ответы, я пометил один из них @KamilMaciorowski, который лучше подходит для заголовка в качестве ответа, но этот ответ @oliv фактически лучше соответствовал моей реальной потребности в моей основной цели. (Для обработки csv-файла с разрывами последовательно в awk.)

Так что в случае, если вы искали в подобных обстоятельствах, я рекомендую сначала проверить это!


Пожалуйста, помогите мне подготовить несколько тысяч файлов CSV, готовых к обработке в awk ! Некоторые поля имеют разрывы строк внутри поля, и поэтому awk обрабатывает их как несколько записей. Однако эти проблемные разрывы строк происходят только тогда, когда вставлено ^ M, поэтому мне просто нужно удалить ^ M и разрыв строки в целом из всех них.

* Эти ^M действительно являются символом разрыва строки, а не буквальной кареткой и буквой M. Этот файл сгенерирован для синтаксического анализа и обработки .net, но я не занимался разработкой приложений ни на одной из сторон создания / чтения файлов, поэтому не знаю, насколько успешно он был проанализирован. Он используется исключительно для полей в определенных столбцах с многострочными строками (комментарии).

Итак, как вы делаете это (CSV с 1 заголовком и 2 записями. В некоторых полях есть разрывы строк, перед которыми стоит ^ M):

"header_1", "header_2", "header_3"
"1-1", "1-2", "1-3"
"2-1", "2-2_a^M
2-2_b^M
2-2_c", "2-3"

как это? (CSV с 1 заголовком и 2 записями без разрывов строк в каждом из них.):

"header_1", "header_2", "header_3"
"1-1", "1-2", "1-3"
"2-1", "2-2_a2-2_b2-2_c", "2-3"

Я попытался удалить их с помощью sed но я слышал, что нет способа обработать, и я не совсем понял причину.

for file in *.csv; do
    sed -e "s/^M//" $file > sedded/$file;
done

Во всяком случае, я получаю это:

"header_1", "header_2", "header_3"
"1-1", "1-2", "1-3"
"2-1", "2-2_a
2-2_b
2-2_c", "2-3"

Я пытался найти что-то вроде "s/^M\n/" , и это не сработало, как я подозревал. Должен ли я использовать совершенно другой инструмент, как vim? Пока он работает одновременно с тысячами файлов (каждый из которых содержит ~ 500 строк, и мне все равно, сколько времени требуется на обработку), я в порядке с любым разрешением. Просто подумал, что sed - это путь. (Я могу использовать команду DOS / PowerShell, если это проще или проще!)

2 ответа2

2

Если эти ^M s действительно являются символами разрыва строки, а не буквальными символами в виде каретки и буквы M, то это то, что мы обозначаем \r , CR или 0x0d (сравните этот мой ответ, начало этого).

Ваша команда

sed -e "s/^M//"

не удаляет \r ; он даже не удаляет буквальный ^M Команда означает «взять строку, найти букву M которая находится в самом начале строки (^ , см. Это), заменить ее ничем.

Примечание sed понимает \r Тем не менее sed -e 's/\r//' не совсем то, что вам нужно. Он удаляет \r но вам также необходимо удалить следующее \n . Вы можете попробовать sed -e 's/\r\n//' , это также не удастся. Проблема в том, что sed - это текстовый инструмент, и он рассматривает \n как разделитель. Выдержка из info sed (выделено мной):

sed работает, выполняя следующий цикл для каждой строки ввода: во-первых, sed читает одну строку из входного потока, удаляет все завершающие символы новой строки и помещает ее в пространство шаблона. Затем команды выполняются; [...].

Это означает, что обычно \n не принадлежит ни одной строке, обработанной с помощью s/… (или другой команды sed ). По этой причине объединение нескольких строк нелегко. Тем не менее это может быть сделано. Это команда, которая вам нужна:

sed -e ': start; /\r$/{ s/\r$//; N; s/\n// }; /\r$/b start'

Объяснение:

  • : start это метка.
  • Если строка содержит \r (т.е. ^M , 0x0d) в самом конце ($), выполните блок {} который:
    • заменить \r в самом конце ни с чем,
    • добавить дополнительную строку из ввода (N),
    • заменить \n которая отделяет дополнительную строку от предыдущих данных.
  • Если результат содержит \r в самом конце (это означает, что дополнительная строка принесла его, поэтому нам нужно добавить еще одну строку), перейдите к start .
1

Предполагая, что в каждой строке 3 поля, а внутри значений нет двойных кавычек, вы можете использовать этот скрипт GNU awk:

awk -v FPAT='"[^"]*"' '{while(NF!=3){p=$0;getline;gsub("^",p)}; p=""}1' file

FPAT определяет, как должно выглядеть поле, то есть все, что окружено двойными кавычками.

Оператор awk создает запись, получая строки из файла, пока не будет 3 поля.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .