
Исходная строка выглядит так:
str-str001-002_01
str-str005-006_05
Я хотел бы извлечь строку перед числом и после подчеркивания, так что это будет выглядеть так:
str-str_01
str-str_05
Я помню, что sed мог разделять шаблоны на группы следующим образом:
sed -n 's/\(^.*\)\([0-9]-[0-9]\)\(.*$\)/\1\3/p'
но он печатает:
str-str0002_01
Затем я вспомнил, что [0-9] — это всего лишь одна цифра, поэтому я попробовал ввести ее со знаком + или *. Тогда это дало пустой результат.
пс: с помощью
echo 'str-str001-002_01' | sed -n 's/\(^.*\)\([0-9]-[0-9]\)\(.*$\)/\2/p'
Я вижу, что это совпадает 1-0
.
Затем я попробовал:
echo 'str-str001-002_01' | sed -n 's/\(^.*\)\([0-9]\+-[0-9]\+\)\(.*$\)/\2/p'
он оставил первые 2 цифры, и только совпадения
1-002
так как же сделать так, чтобы это совпадало001-002
решение1
Это обеспечивает требуемый результат:
sed -nE 's/^([^0-9]*).*_([^_]+)$/\1_\2/p'
Вывод из вашего примера
str-str_01
str-str_05
Объяснение
sed -nE 's/…/…/p'
- Используйте ERE, не печатайте строки, если они не совпадают^
- привязка к началу строки([^0-9]*)
- сопоставить максимально длинный шаблон, содержащий хотя бы один нецифровой символ.*_
- максимально возможное соответствие (включая отсутствие совпадений), затем "_
"([^_]+)
- сопоставить максимально длинный шаблон (не менее одного символа), который не является подчеркиванием$
- прикрепить к концу строки\1_\2
- заменить всю строку с первым(…)
совпадением, "_
", и вторым(…)
совпадением
Причина, по которой ваши попытки не сработали так, как вы ожидали, заключается в том, что *
(and +
) является жадным — он потребляет как можно больше символов, соответствующих предыдущему атому. Поэтому для ERE, (.*)([0-9]+)
примененного к чему-то вроде abc123
, .*
потребит abc12
, оставив [0-9]+
для соответствия только 3
. Вам понадобится "не цифра" чтобы ограничить первое совпадение: ([^0-9]*)([0-9]+)
получить abc
и 123
.
решение2
$ cat file
str-str001-002_01
str-str005-006_05
$ sed 's/[0-9]\{3\}-[0-9]\{3\}//' file
str-str_01
str-str_05
Команда подстановки здесь сопоставляет и удаляет NNN-NNN
строку, NNN
состоящую из трех цифр.
Чтобы соответствоватьхотя бы одинцифра, используйте 1,
вместо 3
:
$ sed 's/[0-9]\{1,\}-[0-9]\{1,\}//' file
str-str_01
str-str_05
Это соответствует использованию +
в расширенном регулярном выражении. Регулярные выражения, используемые sed
по умолчанию, являются "базовыми" регулярными выражениями и +
будут соответствовать литералу плюса. Большинство sed
реализаций также поддерживают расширенные выражения с -E
:
$ sed -E 's/[0-9]+-[0-9]+//' file
str-str_01
str-str_05
Использование *
, как в [0-9]*-[0-9]*
, не сработает, так как это будет соответствовать тире в str-str
(вокруг которого находятся нули).
Если вы чувствуете, что вам действительно нужно сопоставить всю строку и захватить биты, которые вы хотите сохранить, то вы тоже можете это сделать. Следующая команда захватывает начальные нецифровые символы и последний бит, включая подчеркивание:
$ sed 's/\([^0-9]*\).*\(_.*\)/\1\2/' file
str-str_01
str-str_05
Однако, IMHO, это немного сложно расшифровать, и это делает предположения о начале и конце строки, которые вы никогда не упоминали в вопросе. Начало не может, например, содержать цифры перед цифрами, которые вы хотите удалить, и конец строки будет обрезан впоследнийподчеркивание, не обязательно после цифр, которые вы хотите удалить, если в этой части строки есть несколько подчеркиваний.
Вы всегда можете что-то добавить к этому выражению, чтобы гарантировать, что NNN-NNN
не будет захвачен только этот бит, но это еще больше затруднит понимание выражения.