bash: come utilizzare più manipolazioni di stringhe (espansione dei parametri) in un unico passaggio?

Aug 15 2020

Ho string=substr1-substr2-substr3.substr4dove le sottostringhe sono di lunghezza variabile. Voglio estrarre substr3da stringe sto pensando di farlo utilizzando le ${string##pattern}e ${string%pattern}espansioni manipolazione delle stringhe. Utilizzando questo approccio, è chiaro che devo eseguire ${string##*-}ed eseguire ${string%.*}l'espansione risultante, o viceversa. Le mie domande sono:

  1. è questa la scelta migliore?
  2. Se sì, come posso eseguire entrambi in un unico passaggio? Quando provo a fare qualcosa di simile ${string##*-${string%.*}}o ${string%.*${string##*-}}ricevo semplicemente l'intera stringa. Mi rendo conto che potrei sempre fare l'estrazione in due passaggi assegnando una variabile intermedia al risultato del primo passaggio e poi manipolandolo; ma voglio farlo in un solo passaggio. Come posso procedere?

TIA!

Risposte

2 ilkkachu Aug 15 2020 at 20:39

Dato

string=substr1-substr2-substr3.substr4

${string%.*} è

substr1-substr2-substr3

così ${string##*-${string%.*}}è

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

che significa rimuovere dall'inizio di string, tutto fino ae incluso -substr1-substr2-substr3. Ma non esiste una sottostringa di questo tipo string, poiché non c'è un trattino davanti substr1, quindi ottieni la stringa originale.

Quello che probabilmente vuoi è

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

che porta al resultcontenimento substr3.

In Zsh, potresti farlo in un unico passaggio:, ma non funziona in Bash.result=${${string%.*}##*-}

In Bash, sei limitato all'uso di espansioni sul lato destro di #o %, e questo non ti aiuta qui poiché devi rimuovere parti sia dall'inizio che dalla fine della stringa.


In alternativa, se $stringnon contiene caratteri di nuova riga, puoi usare

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

e leggere substr3da c.

In tal caso, a seconda della shell e della dimensione della stringa, il contenuto di $stringverrà memorizzato in un file temporaneo o alimentato attraverso una pipe che readleggerà la prima riga e la dividerà in base a $IFS.