Вопрос или проблема
У меня есть это, что почти делает то, что я хочу
git show-branch --current $SHA1 \
| sed --quiet --regexp-extended \
's/^.*\* \[[a-z]+\/(B-[0-9]+)-([a-z0-9-]+)\].*/\1 \2/p' \
| sed --quiet 2p
и выводит
B-47120 java-11-take2
git show-branch
выводит это
! [62cba3e2b3ba8e1115bceba0179fea6c569d9274] B-48141 remove env prefix
* [ccushing/B-47120-java-11-take2] B-48141 remove env prefix
--
* [ccushing/B-47120-java-11-take2] B-48141 remove env prefix
+* [62cba3e2b3ba8e1115bceba0179fea6c569d9274] B-48141 remove env prefix
желаемый вывод
B-47120 java 11 take2
что заменяет -
во второй группе захвата, но я не могу придумать способ заменить -
только во второй части, так как мне нужно также захватить её.
Я использую git для windows и ограничен инструментами, предоставляемыми с ним. Хотя, вероятно, есть более программные способы сделать это (я мог бы использовать Perl), я хотел бы увидеть ответ с использованием sed
, если это возможно.
ОБНОВЛЕНИЕ
потому что, видимо, это не очевидно. Шаблон представляет собой username/ticketid-description
(минус то, что требуется, чтобы получить это из git show-branch
).
- имя пользователя всегда должно быть буквенным
- ticketid всегда в формате
B-\d+
- описание (
\2
может содержать произвольное количество-
, которые следует преобразовать в пробелы
Я пытаюсь программно превратить это в заголовочную строку git для хуков prepare-commit-msg
git
.
Попробуйте следующее:
... |sed -nE '/^[[:blank:]*]+\[[^/]*\/(B-[0-9]+)-([^]]*)\].*/{
s//\1 \2/; :a s/(B-[0-9]+ [^-]*)-(.*)/\1 \2/;ta; p; }'
Советы:
[^X]*
: совпадает с любым символом кроме символаX
(а также, исключением\n
овая строка).[^X]*X
: совпадает с любым символом кроме символаX
(а также\n
овая строка) с последующим символомX
.(...)
: захватывает групповой матч с обратными ссылками\1
для первого,\2
для второго и так далее (вы можете использовать до\9
обратных ссылок).:label s/find/replace/; t label
: переход кlabel
при успешной замене и повторение команды.
Или немного короче (в зависимости от формата ввода):
... |sed -nE '/^[^/]*\/([^]]*)\].*/{
s//\1/; :a s/(B-[0-9]+)(.*)-([^-]*)$/\1\2 \3/;ta; p; }'
Я предлагаю следующее, предполагая несколько вещей, упомянутых ниже (сообщите, если эти предположения неверны):
# выбрать строку с символом слэша "https://unix.stackexchange.com/"
# заменить первый '-' на другой недопустимый символ, например '@'
# заменить все '-' на пробелы
# заменить '@' на '-'
# захватить все между "https://unix.stackexchange.com/" и ']', удалить все остальное
$ sed -n -e '\:/:{s:-:@:;s:-: :g;s:@:-:;s:^.*/\([^]]*\).*:\1:p;q}'
B-47120 java 11 take2
\:/:
выбрать строки, содержащие слэш /
.
* [ccushing/B-47120-java-11-take2] B-48141 remove env prefix
s:-:@:
заменить -
на @
, не жадно, поэтому только первый.
* [ccushing/B@47120-java-11-take2] B-48141 remove env prefix
s:-: :g
заменить -
на пробел, жадно.
* [ccushing/B@47120 java 11 take2] B 48141 remove env prefix
s:@:-:
заменить @
на -
* [ccushing/B-47120 java 11 take2] B 48141 remove env prefix
s:^.*/\([^]]*\).*:\1:p;q
захват между /
и ]
, удаление всего остального, печать и выход.
B-47120 java 11 take2
С конструкциями GNU sed вы можете получить вывод, как показано.
Примечание: я не изменял ваши регулярные выражения, только подправил некоторые части.
Измените {2}
на {4}
, если, допустим, вам понадобится четвертое совпадение.
sed --quiet --regexp-extended '
s/^.*\* \[[a-z]+\/(B-[0-9]+)-([a-z0-9-]+)\].*/\1 \2/;T;G
s/\n{2}$//;Ta
s/-/ /2gp;q
:a;z;H
' file
Это более универсальный скрипт, но я пытался решить аналогичную проблему. Ответ заключается в части s/-/ /2g однострочника. Начинайте со второго экземпляра, а затем замените остальные глобально. Это официально неопределенное поведение, но работает в GNU sed.
sed -n -E -e ‘s/-/ /2g’ -e ‘s/^.[[a-z]+/([A-Z]-.)].$/\1/g’ -e ‘/^[A-Z].$/p’ git-test.txt
.
Ответ или решение
Для решения вашей задачи, где требуется использовать sed
для замены символов в захваченной группе, мы можем пошагово разобрать, как достичь требуемого результата.
Теория:
Использование sed
для обработки строк, извлечённых из терминальных команд таких, как git show-branch
, часто встречается в автоматизации текстовой обработки. Здесь основной задачей является извлечение и модификация конкретных частей индивидуальной строки из выходных данных команды. В текущем контексте у нас есть строка вида [username/B-ticketid-description]
, из которой мы хотим извлечь части ticketid
и description
, заменив все дефисы в description
на пробелы.
sed
— это фильтр потокового редактирования (stream editor), который может выполнять различные манипуляции с текстом напрямую на выходе терминала или в файле. Один из его сильных аспектов — это поддержка регулярных выражений, с помощью которых мы можем находить и заменять текстовые шаблоны.
Пример:
Вы уже предоставили пример ввода и желаемого результата:
- Вход:
* [ccushing/B-47120-java-11-take2] B-48141 remove env prefix
- Ожидаемый выход:
B-47120 java 11 take2
Ваша текущая команда sed
выглядит так:
git show-branch --current $SHA1 \
| sed --quiet --regexp-extended \
's/^.*\* \[[a-z]+\/(B-[0-9]+)-([a-z0-9-]+)\].*/\1 \2/p' \
| sed --quiet 2p
Она уже осуществляет захват двух частей требуемой строки. Однако маленькая проблема заключается в том, что после захвата второго фрагмента требуется заменить в нём дефисы пробелами.
Применение:
Предложенное решение, чтобы этого достичь, будет использовать многошаговую замену и адресацию в sed
. Например:
- Сначала мы выделяем несколько подходящих строк, содержащих шаблон, с помощью выражения выбора
/^[[:blank:]*]+\[[^/]*\/(B-[0-9]+)-([^]]*)\].*/
. - Используем захватывающие группы для выбора нужной части строки, потом в контексте этой выборки заменяем все
-
в ней на пробелы.
Рассмотрите это пошаговое решение:
git show-branch --current $SHA1 | sed -nE '/^[[:blank:]*]+\[[^/]*\/(B-[0-9]+)-([^]]*)\].*/{
s//\1 \2/; :a s/(B-[0-9]+ [^-]*)-(.*)/\1 \2/;ta; p; }'
Данная команда выполняет следующее:
- Подбирает строки с требуемым шаблоном.
- Далее из этих строк извлекает
${1} \2
с помощьюs//\1 \2/
, где\1
— этоticketid
, а\2
—description
. - Циклично заменяет
-
вdescription
на пробелы с использованием метки:a
и команды заменыs/(B-[0-9]+ [^-]*)-(.*)/\1 \2/;ta
.
Данная применение sed
позволяет гибко манипулировать строками, изменяя только те части, которые вам нужны, без необходимости в сложных скриптах на других языках программирования.
Практический пример:
Продолжая использовать те же принципы, можно адаптировать подход для других сценариев, таких как извлечение различных шаблонов из текстовых данных, которые могут появляться в системных журналах, выходных данных команд UNIX и во многих других областях, где информация представлена в текстовом формате. В вашей ситуации, sed
может быть частью скрипта на хук prepare-commit-msg
, что позволяет автоматизировать формирование заголовков коммитов, что критично при больших объемах работы в корпоративной среде или в распределённых командах.
Таким образом, с помощью такого подхода можно сохранить консистентность и структурированность, помогая командам разработки фокусироваться на содержании коммитов больше, чем на соблюдении формальных требований к их оформлению.