bash: Как использовать несколько строковых манипуляций (расширение параметров) за один шаг?

Aug 15 2020

У меня string=substr1-substr2-substr3.substr4где подстроки переменной длины. Я хочу извлечь substr3из него stringи подумываю сделать это с помощью расширений ${string##pattern}и ${string%pattern}строковых манипуляций. Используя этот подход, ясно, что мне нужно запустить ${string##*-}и запустить ${string%.*}получившееся расширение или наоборот. Мои вопросы:

  1. это лучший выбор?
  2. Если да, как мне запустить оба за один шаг? Когда я пытаюсь сделать что-то вроде ${string##*-${string%.*}}или ${string%.*${string##*-}}просто получаю полную строку. Я понимаю, что всегда могу выполнить извлечение в два этапа, назначив промежуточную переменную результату первого шага, а затем манипулируя этим; но я хочу сделать это за один шаг. Как мне это сделать?

TIA!

Ответы

2 ilkkachu Aug 15 2020 at 20:39

Дано

string=substr1-substr2-substr3.substr4

${string%.*} является

substr1-substr2-substr3

Итак, ${string##*-${string%.*}}это

${string##*-substr1-substr2-substr3}

что означает удалить с самого начала stringвсе до и включительно -substr1-substr2-substr3. Но такой подстроки нет string, так как перед ней нет тире substr1, поэтому вы получаете исходную строку.

Вы, вероятно, хотите

string=substr1-substr2-substr3.substr4
result="${string%.*}" result="${result##*-}"

что приводит к resultcontaing substr3.

В Zsh вы можете сделать это за один шаг:, но в Bash это не работает.result=${${string%.*}##*-}

В Bash вы ограничены использованием расширений в правой части #или %, и это вам здесь не поможет, поскольку вам нужно удалить части как из начала, так и из конца строки.


В качестве альтернативы, если $stringне содержит символов новой строки, вы можете использовать

IFS=.- read -r a b c d <<< "$string"

и читать substr3с c.

В этом случае, в зависимости от оболочки и размера строки, содержимое $stringбудет либо сохранено во временном файле, либо пропущено через канал, который readбудет читать первую строку из и разделять ее в соответствии с $IFS.