bash: Jak w jednym kroku używać wielu operacji na ciągach znaków (rozwijania parametrów)?

Aug 15 2020

Mam string=substr1-substr2-substr3.substr4gdzie podciągi mają zmienną długość. Chcę wyodrębnić substr3z stringi myślę o zrobieniu tego za pomocą rozszerzeń ${string##pattern}i ${string%pattern}manipulacji ciągami. Korzystając z tego podejścia, jasne jest, że muszę uruchomić ${string##*-}i uruchomić ${string%.*}wynikowy dodatek lub odwrotnie. Moje pytania to:

  1. czy to najlepszy wybór?
  2. Jeśli tak, jak uruchomić oba w jednym kroku? Kiedy próbuję zrobić coś podobnego ${string##*-${string%.*}}lub ${string%.*${string##*-}}po prostu odzyskuję pełny ciąg. Zdaję sobie sprawę, że zawsze mógłbym przeprowadzić wyodrębnianie w dwóch krokach, przypisując zmienną pośrednią do wyniku pierwszego kroku, a następnie manipulując tym; ale chcę to zrobić w jednym kroku. Jak mam się do tego zabrać?

TIA!

Odpowiedzi

2 ilkkachu Aug 15 2020 at 20:39

Dany

string=substr1-substr2-substr3.substr4

${string%.*} jest

substr1-substr2-substr3

tak ${string##*-${string%.*}}jest

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

co oznacza usunięcie od początku stringwszystkiego do włącznie -substr1-substr2-substr3. Ale nie ma takiego podciągu string, ponieważ przed nim nie ma myślnika substr1, więc otrzymujesz oryginalny ciąg.

To, czego prawdopodobnie chcesz, to

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

co prowadzi do resultzakażenia substr3.

W Zsh można to zrobić w jednym kroku: ale to nie działa w Bash.result=${${string%.*}##*-}

W Bash jesteś ograniczony do używania rozszerzeń po prawej stronie #lub %, a to ci nie pomaga, ponieważ musisz usunąć części zarówno z początku, jak i końca ciągu.


Alternatywnie, jeśli $stringnie zawiera znaków nowej linii, możesz użyć

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

i czytać substr3off z c.

W takim przypadku, w zależności od powłoki i rozmiaru łańcucha, zawartość $stringbędzie przechowywana w pliku tymczasowym lub przesyłana przez potok, który readodczyta pierwszą linię z i podzieli ją zgodnie z $IFS.