Для обмана необходимы две части:
Прекратите замену, когда вы достигнете закрывающей квадратной скобки (но сделайте это несколько раз в строке):
s/\(\[[^] ]*\) /\1_/g
Это соответствует открытой квадратной скобке, за которой следует ноль или более символов, которые не являются ни пробелом, ни закрывающей квадратной скобкой. Глобальный суффикс означает, что шаблон применяется ко всем последовательностям, начинающимся с открытой квадратной скобки, за которой в конце концов следует пустая или закрытая квадратная скобка в строке. Также обратите внимание, что это регулярное выражение не меняет '[single-word] and context
', тогда как оригинал переведет его в '[single-word]_and context
', который не является объектом упражнения.
Получите sed, чтобы повторить поиск с того места, где этот начался. К сожалению, нет действительно хорошего способа сделать это. Sed всегда возобновляет поиск после замещенного текста; и это один раз, когда мы этого не хотим. Иногда вы можете просто повторить операцию замены. В этом случае вы должны повторять это каждый раз, когда замена завершается успешно, останавливаясь, когда нет больше замен.
Двумя менее известными операциями в sed
являются команды :label
и t
. Они присутствовали в 7-м издании Unix (около 1978 г.), поэтому они не являются новыми функциями. Первый просто определяет позицию в скрипте, к которой можно перейти с помощью 'b
' (здесь не требуется) или 't
':
[2addr]t [label]
Переход к функции ':
' с меткой, если были произведены какие-либо замены после самого последнего чтения строки ввода или выполнения функции t
. Если метка не указана, переходите к концу скрипта.
Изумительно: нам нужно:
sed -e ':redo; s/\(\[[^] ]*\) /\1_/g; t redo' data.file
За исключением - он не работает все в одной строке, как эта (по крайней мере, не в MacOS X). Это сработало превосходно, хотя:
sed -e ':redo
s/\(\[[^] ]*\) /\1_/g
t redo' data.file
Или, как отмечено в комментариях, вы можете написать три отдельных параметра '-e' (которые работают в MacOS X):
sed -e ':redo' -e 's/\(\[[^] ]*\) /\1_/g' -e 't redo' data.file
С учетом файла данных:
a line with [one blank] word inside square brackets.
a line with [two blank] or [three blank] words inside square brackets.
a line with [no-blank] word inside square brackets.
a line with [multiple words in a single bracket] inside square brackets.
a line with [multiple words in a single bracket] [several times on one line]
вывод из показанного сценария sed:
a line with [one_blank] word inside square brackets.
a line with [two_blank] or [three_blank] words inside square brackets.
a line with [no-blank] word inside square brackets.
a line with [multiple_words_in_a_single_bracket] inside square brackets.
a line with [multiple_words_in_a_single_bracket] [several_times_on_one_line]
И, наконец, читая мелкий шрифт в вопросе, если вам нужно, чтобы это было сделано только в первом поле в квадратных скобках в каждой строке, тогда мы должны убедиться, что нет открытых квадратных скобок перед тем, который начинает соответствие , Этот вариант работает:
sed -e ':redo' -e 's/^\([^]]*\[[^] ]*\) /\1_/' -e 't redo' data.file
(Квалификатор 'g' пропал - он, вероятно, не нужен в других вариантах также с учетом цикла; его присутствие может сделать процесс незначительно более эффективным, но, скорее всего, это будет практически невозможно обнаружить. шаблон теперь привязан к началу строки (каретки) и содержит ноль или более символов, которые не являются квадратными скобками перед первой открытой квадратной скобкой.)
Пример вывода:
a line with [two_blank] or [three blank] words inside square brackets.
a line with [no-blank] word inside square brackets.
a line with [multiple_words_in_a_single_bracket] inside square brackets.
a line with [multiple_words_in_a_single_bracket] [several times on one line]