Элегантный способ объединения строк с разделителем из нескольких -символов -, игнорирование пустых строк, поддержка \n, \r или \r\n

Похоже, у вас отсутствуют некоторые зависимости, которые не позволяют dpkg выполнить ваш запрос. Я рекомендую запустить команду sudo apt-get -f installи проверить, что она предлагает, чтобы решить проблему. Если вы согласны с предложенными изменениями, нажмите Y и дайте ему запуститься.

3
14.10.2020, 10:47
5 ответов

Элегантность может исходить от правильного регулярного выражения. Вместо того, чтобы менять каждый \rна \n(s/\r/\n/g), вы можете преобразовать каждый разделитель строки \r\n, \r, \nв разделитель, который вы хотите (в GNU sed, поскольку немногие реализации sed поймут \r, и не все поймут-E):

sed -E 's/\r\n|\r|\n/; /g'

Или, если вы хотите удалить пустые строки, любой запуск таких разделителей строк:

sed -E 's/[\r\n]+/; /g'

Это сработает, если мы сможем захватить все символы конца строки в пространстве шаблонов. Это означает, что нужно загружать весь файл в память, чтобы иметь возможность редактировать его.

Итак, вы можете использовать более простую (одну команду для GNU sed):

sed -zE 's/[\r\n]+/; /g; s/; $/\n/' "$filepathvar"

-zпринимает нулевые байты в качестве разделителей строк, эффективно получая все \rи \nв пространстве шаблонов.

s/[\r\n]+/; /gпреобразует все типы разделителей строк в нужную строку.

s/; $/\n/преобразует (последний )завершающий разделитель в фактическую новую строку.


Примечания

Опция -zsed означает использование нулевого разделителя (0x00 ). Использование этого разделителя началось с необходимости поиска, чтобы иметь возможность обрабатывать имена файлов с символами новой строки (-print0), которые будут соответствовать параметру xargs (-0). Это означало, что некоторые инструменты также были модифицированы для обработки строк с нулевым разделителем.

Это не -опция posix, которая разбивает файлы на нули вместо новой строки.

Текстовые файлы Posix не должны иметь нулевых (NIL )байтов, поэтому использование этой опции на практике означает захват всего файла в памяти перед его обработкой.

Разрыв файлов на NIL означает, что символы новой строки перестают редактироваться в пространстве шаблонов sed. Если в файле есть несколько байтов NIL, эта идея по-прежнему работает правильно для новых строк, поскольку они по-прежнему доступны для редактирования в каждом фрагменте файла.

Опция -zдобавлена ​​в GNU sed.ATT sed (, на котором был основан posix ), не имел такой опции (и до сих пор не имеет ), некоторые BSD sed также до сих пор не имеют.

Альтернативой варианту -zявляется запись всего файла в память. Некоторыми способами это можно было бы сделать :

.
sed 'H;1h;$!d'          # capture whole file in hold space.
sed ':a;N;$!ba'         # capture whole file in pattern space.

Наличие всех новых строк (, кроме последней )в пространстве шаблона, позволяет редактировать их:

sed -Ee 'H;1h;$!d;x'   -e 's/(\r\n|\r|\n)/; /g

Со старыми sed также требуется использовать более длинный и более явный (\r\n|\r|\n)+вместо [\r\n]+, потому что такие sed не понимают выражения \rили \nвнутри квадратных скобок [].

Линейная ориентация

Решение, которое работает по одной строке за раз (и \rтакже является допустимым ограничителем строки в этом решении ), что означает, что нет необходимости хранить весь файл в памяти (меньше используемая память )возможна с GNU awk:

awk -vRS='[\r\n]+' 'NR>1{printf "; "}{printf $0}END{print ""}'  file

Должен быть GNU awk из-за разделителя записей регулярных выражений [\r\n]+. В других awk разделитель записей должен быть один байт.

4
18.03.2021, 22:57

Просто используйте perl. Sed сложнее использовать с символами новой строки, но Perl с ними легко справляется:

printf 'aa\nbb\ncc\n' > file
printf 'aa2\r\nbb2\r\ncc2\r\n' > file2
printf 'aa3\rbb3\rcc3\r' > file3

Итак, fileимеет \nокончания строк, file2имеет \r\nи file3имеет \r(, что устарело в наши дни, кстати, нет особого смысла поддерживать его ). Теперь объедините их в строку:

$ joined_string_var=$(perl -pe 's/(\r\n|\r|\n)/; /g' file file2 file3)
$ echo "$joined_string_var"
aa; bb; cc; aa2; bb2; cc2; aa3; bb3; cc3; 

Вам понадобится второй проход, чтобы удалить завершающий разделитель ; , хотя:

$ joined_string_var=$(perl -pe 's/(\r\n|\r|\n)/; /g' file file2 file3 | sed 's/; $//')
$ echo "$joined_string_var" 
aa; bb; cc; aa2; bb2; cc2; aa3; bb3; cc3

Или удалите его в perl:

$ joined_string_var=$(perl -ne 's/(\r\n|\r|\n)/; /g; $k.=$_; END{$k=~s/; $//; print $k}' file file2 file3)
$ echo "$joined_string_var" 
aa; bb; cc; aa2; bb2; cc2; aa3; bb3; cc3
4
18.03.2021, 22:57

Для записи вzsh(для тех, кто приходит сюда с аналогичным требованием, но не с bashограничением ), вы должны сделать:

IFS=$'\r\n'
joined=${(j[; ])$(<$filepathvar):#}
  • IFS=$'\r\n'устанавливает разделитель полей для разделения слов на символы CR или LF (с использованием стиля ksh93 -$'...'кавычки ).
  • $(<file):, как и в ksh, расширяется до содержимогоfile(без завершающих символов новой строки ), с учетом разделения слов.
  • ${list:#pattern}расширяется до элемента списка, который не соответствуетpattern(и расширению до ksh's${list#pattern}). Здесь с пустой строкой в ​​качестве шаблона для удаления пустых строк.
  • ${(j[; ])list}jобъединяет элементы списка с "; ".
3
18.03.2021, 22:57
f=file
python3 -c "import re
print(re.sub(r'[\r\n]+', '; ', open('$f').read().strip('\r').strip('\n')))"
perl -nF'[\r\n]+' -0777E '$,="; ";
  say @F;
' file
0
18.03.2021, 22:57

Возможно, элегантный, но явно не -переносимый вариант GNU awk, использующий функциюjoinиз библиотеки , поставляемой вместе с самим gawk:

.
joined_string=$(awk -i join -v RS='[\n\r]+' -v sep='; ' '
  { a[++i] = $0 } END { print join(a, 1, i, sep) }
' "$filepathvar")

Аргументами функции joinявляются :массив для объединения (a), позиция начального элемента (1), позиция конечного элемента (i), строка для использования в качестве разделителя(sep).

Нестандартная -опция GNU awk-i(или--include)используется для расширения его возможностей путем загрузки исходных библиотек. Интерпретация RSкак регулярного выражения также является расширением стандарта , поддерживаемого GNU awkи некоторыми другими реализациями (, например. mawk, BusyBoxawk).

Обратите внимание, что этот подход не подходит для больших объемов данных, поскольку весь файл должен храниться в памяти.

1
18.03.2021, 22:57

Теги

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