Как извлечь часть строки с помощью sed?

Я уже нашла подобный чехол проверьте В моем случае имя файла: backup_20240827000025.sql, мне нужно извлечь символы с помощью sed - 20240827. Для этой строки я пытаюсь выполнить sed с регулярным выражением в centos7 sed (GNU sed) 4.2.2.

string=backup_20240827000025.sql
echo $string | sed -r  's/\./[a-z]{6}\w\([0-9]{8}\)[0-9]+\.[a-z]{3}/\1/p'
Error:
sed: -e expression #1, char 49: invalid reference \1 on `s' command's RHS

Если я удалю \ обратную косую черту, окружающую круглые скобки

\./[a-z]{6}\w([0-9]{8})[0-9]+\.[a-z]{3},

затем я получаю свою строку обратно в том виде, в котором она была:

./backup_20240827000025.sql

Однако, если я использую Python и это регулярное выражение

'\./[a-z]{6}\w([0-9]{8})[0-9]+\.[a-z]{3}' 

он работает хорошо и выдает результат типа 20240827. Может ли кто-нибудь помочь с этим? Спасибо.

Если ведущий backup_ постоянный, sed вам не нужен. Попробуйте echo "${string:7:8}".

Renaud Pacalet 27.08.2024 17:44

string не начинается с ./, но ваша модель, похоже, предполагает ведущую ./. Кроме того, string содержит _ после слова backup, и ваш шаблон, похоже, не учитывает это. Поскольку шаблон вообще не будет совпадать, попытка использовать \1 не удалась.

William Pursell 27.08.2024 19:10
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
51
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Можете ли вы попробовать более простое регулярное выражение?

$ string=backup_20240827000025.sql
$ echo "$string" | sed -r 's/backup_([0-9]{8}).*/\1/'
20240827

спасибо за помощь, проверил, работает, но в чем причина моей ошибки? Все выглядит хорошо. Я просто пытаюсь понять.

Stanislav 27.08.2024 17:50
Ответ принят как подходящий

Ваша входная строка не начинается с ./, поэтому ваше регулярное выражение вообще не соответствует. Аналогично, \* соответствует буквальной звездочке, но во входной строке ее нет.

Непонятно, зачем удваивать звездочки и прочие квантификаторы; это синтаксические ошибки.

\w не является переносимым, хотя, вероятно, поддерживается в CentOS.

С помощью простого, хорошо сформированного регулярного выражения вы получаете

bash$ echo "backup_20240827000025.sql" |
> sed -r -n 's/[a-z]{6}[^a-z0-9]*([0-9]{8})[0-9]+\.[a-z]{3}/\1/p'
20240827

Это была моя опечатка. Итак, исходная строка: ./backup_20240822000015.sql Звездочки были добавлены случайно. Исходное регулярное выражение было \./[a-z]{6}\w([0-9]{8})[0-9]+\.[a-z]{3} Но я попробовал заменить \w на _ или . но все равно безрезультатно.

Stanislav 27.08.2024 17:57

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

tripleee 27.08.2024 18:39

Устранение ошибки ОП...

Без опции -r вы должны указать sed, когда круглые скобки должны использоваться для обозначения группы захвата. Вы делаете это, экранируя круглые скобки, окружающие группу захвата, например:

$ x=abcdef

$ sed 's/.*\(cd\).*/XX\1XX/' <<< "${x}"
XXcdXX

Если вы используете опцию -r, вам больше не нужно экранировать скобки (т. е. скобки рассматриваются как специальные символы), например:

$ sed -r 's/.*(cd).*/XX\1XX/' <<< "${x}"
XXcdXX

Фактически, если вы используете опцию -r, вам не нужно экранировать круглые скобки, заключающие в себя группу захвата. Когда вы экранируете скобки, вы сообщаете sed, что это буквальные скобки (т. е. не рассматриваете их как специальные символы). В случае OP комбинация -r и экранированных скобок оставляет команду sed без групп захвата, что, в свою очередь, означает, что обозначение \1 относится к несуществующей/недействительной ссылке:

$ sed -r 's/.*\(cd\).*/XX\1XX/' <<< "${x}"
      ^^      ^^  ^^     ^^
sed: -e expression #1, char 20: invalid reference \1 on `s' command's RHS

Итак, вызов OP sed должен выглядеть так:

sed -r 's/\./[a-z]{6}\w([0-9]{8})[0-9]+\.[a-z]{3}/\1/p'
                        ^        ^ ---- parents are not escaped

Но теперь ОП сталкивается с другими проблемами...

\./[a-z]{6} говорит, что мы ищем строку, состоящую из литералов . (точка) + / (косая черта) + [a-z]{6} (6 символов нижнего регистра). Но образцы данных OP не включают буквальные символы . + /, поэтому мы не видим никаких изменений:

$ echo "$string" | sed -r 's/\./[a-z]{6}\w([0-9]{8})[0-9]+\.[a-z]{3}/\1/p'
backup_20240827000025.sql

Наша первая попытка решить эту последнюю проблему — удалить \./, но затем мы столкнулись с новой проблемой:

$ echo "$string" | sed -r 's/[a-z]{6}\w([0-9]{8})[0-9]+\.[a-z]{3}/\1/p'
20240827
20240827

Двойной выход?

По умолчанию sed автоматически распечатает пространство шаблонов (первый 20240827), в то время как операция /p говорит о необходимости снова явно распечатать пространство шаблонов (2-й 20240827).

Чтобы ограничить вывод одной копией пространства шаблонов, у нас есть несколько вариантов:

######
# add '-n' to suppress automatic printing of the pattern space

echo "$string" | sed -r -n 's/[a-z]{6}\w([0-9]{8})[0-9]+\.[a-z]{3}/\1/p'
                        ^^
######
# or remove the 'p' operation

echo "$string" | sed -r 's/[a-z]{6}\w([0-9]{8})[0-9]+\.[a-z]{3}/\1/'

Оба из них будут генерировать единое пространство шаблонов:

20240827

Следует иметь в виду один момент, связанный с производительностью...

При передаче вывода одной команды на вторую команду оболочка запускает подпроцесс для второй команды. Создание подпроцесса требует относительно больших затрат ресурсов и времени и становится весьма заметным при создании чрезмерного количества подоболочек.

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

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

Одна из идей заключалась в том, чтобы исключить ненужные echo в пользу строки здесь:

$ sed -r 's/[a-z]{6}\w([0-9]{8})[0-9]+\.[a-z]{3}/\1/' <<< "$string"
20240827                                              ^^^^^^^^^^^^^

В качестве альтернативы, поскольку OP, похоже, работает со строками фиксированной длины, мы можем использовать функцию bash's подстроки ("${var:start:length}"):

$ echo "${string:7:8}"

ПРИМЕЧАНИЕ: первый символ находится на позиции 0.

Если мы имеем дело с переменным количеством символов перед _, мы можем использовать подстановку параметра :

$ dt = "${string#*_}"                     # strip off leading <string1>_
$ typeset -p dt
declare -- dt = "20240827000025.sql"

$ echo "${dt:0:8}"                      # now use the substring feature
20240827

В примере OP мы просто хотим напечатать подстроку на стандартный вывод. Если OP необходимо зафиксировать подстроку в переменной, то у нас возникает еще одна проблема с производительностью...

Следующее также создаст подоболочку ($( command ... )):

$ newvar=$( sed -r 's/[a-z]{6}\w([0-9]{8})[0-9]+\.[a-z]{3}/\1/' <<< "$string" )
$ typeset -p newvar
declare -- newvar = "20240827"

Хорошей новостью является то, что мы можем повторно использовать решения по замене параметров и подстрокам, чтобы устранить эту дополнительную подоболочку.

$ newvar = "${string:7:8}"
$ typeset -p newvar
declare -- newvar = "20240827"

$ dt = "${string#*_}" 
$ newvar = "${dt:0:8}"
$ typeset -p newvar
declare -- newvar = "20240827"

Другие вопросы по теме

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

Как использовать регулярное выражение для извлечения набора определенных подстрок?
Негативный просмотр, похоже, не работает должным образом
Объединить многострочные строки в фрейме данных pandas на основе шаблона регулярного выражения
Регулярное выражение для текста, разделенного запятыми, с необязательными двойными кавычками, которые могут содержать кавычки, экранированные обратной косой чертой
Почему эта замена регулярного выражения с использованием захвата зависает в этом быстром коде?
Токенизация XSLT с помощью регулярного выражения для токенизации только в том случае, если за точкой с запятой не следует пробел и число
Regex соответствует определенным шаблонам URL-адресов
Используйте одно регулярное выражение для извлечения информации из двух шаблонов
Регулярное выражение для соответствия начальной нумерации или алфавитным маркерам, например (a)
Как включить проверку наличия большего количества пробелов в негативном виде?