La stringa di Bash sostituisce più caratteri con uno


8

Sto sostituendo, da un titolo di feed, tutti i caratteri tranne le lettere e le cifre con un trattino per utilizzare il risultato come nome file sicuro per qualsiasi file system:

$ t="Episodie 06: No hope of riding home (NEW) - Advanced grammar"
$ echo ${t//[^A-Za-z0-9]/-}
Episodie-06--No-hope-of-riding-home--NEW----Advanced-grammar

Comunque mi piacerebbe condensare tutti i trattini ripetuti con un solo like Episodie-06-No-hope-of-riding-home-NEW-Advanced-grammar

Ho scoperto che posso ottenerlo usando una sostituzione a due passaggi:

$ t="Episodie 06: No hope of riding home (NEW) - Advanced grammar"
$ tmp=${t//[^A-Za-z0-9]/-}
$ echo ${tmp//--/-}
Episodie-06-No-hope-of-riding-home-NEW--Advanced-grammar

Pensavo di poterlo fare in un unico passaggio come:

$ echo ${t//[^A-Za-z0-9]+/-}

ma non funziona.

Qualche idea?

Nota: non voglio andare con sedo altri strumenti

Risposte:


8

Hai bisogno di qualcosa di più potente dei tradizionali caratteri jolly della shell. In bash, imposta l' extglobopzione, che ti dà accesso alle espressioni regolari in modelli glob attraverso una sintassi insolita ereditata da ksh.

shopt -s extglob
sanitized=${raw//+([^A-Za-z0-9])/-}

Grazie, c'è stato un commento da Fered in risposta jw013 con questa soluzione. Alcune informazioni sulla compatibilità con altre shell di questa sintassi? Non mi preoccupo così tanto, solo per saperne di più shopte su quali shell lo supportano.
neurino,

@neurino shoptè specifico per bash. La sintassi del pattern che abilita è sempre disponibile in tutte le varianti di ksh. In zsh, questa sintassi deve essere abilitata con setopt ksh_glob. POSIX non ha questa caratteristica, i suoi caratteri jolly sono meno potenti di regexps. Conchiglie diverse da bash / ksh / zsh, che in pratica significa principalmente cenere al giorno d'oggi, tendono ad attenersi ai caratteri jolly POSIX.
Gilles 'SO- smetti di essere malvagio'

bene, a questo punto preferisco compatibilità e flessibilità più con un po 'più in alto: echo "$t" | sed -r 's/[^[:alnum:]]+/-/g; s/^-|-$//'. Accetto la tua risposta in quanto fa esattamente ciò che è stato chiesto.
neurino,

@neurino Se vuoi la portabilità su altre shell, puoi andare con la risposta di Glenn Jackman . A proposito, nota che il ${var/PATTERN/REPLACEMENT}costrutto è anche specifico di ksh / bash / zsh.
Gilles 'SO- smetti di essere malvagio'

Preferisco sedcome conosco meglio la sua sintassi e il comportamento, posso facilmente aggiungere un'istruzione per rimuovere i trattini di avvio / trascinamento, non ho bisogno di preoccuparmi del \ncarattere. È sedmolto meno disponibile di tr?
neurino,

7

tr è un buon strumento per questo lavoro

new=$( printf "%s" "$t" | tr -cs 'a-zA-Z0-9' '-' )
new=${new#-}; new=${new%-}

Grazie, +1, non mi ricordo mai di tr... Comunque stavo cercando di farlo a Bash, altrimenti andrei con sed:echo "$t" | sed -r 's/[^A-Za-z0-9]+/-/g'
neurino

Down ha votato perché è in conflitto conNote: I don't want to go with sed or other tools
Paul Calabro,

3

Se vuoi rimanere con puro bash, dovrai accontentarti della soluzione a due passaggi. Le sostituzioni di stringhe Bash usano globs , come nell'espansione del percorso e non espressioni regolari. Gli unici caratteri speciali in gocce sono *, ?e [], il cui ruvido equivalenti nelle espressioni regolari sono .*, .e []. Dai un'occhiata al wiki di Wooledge e alle sezioni della pagina man su e per maggiori informazioni.bash(1)Parameter ExpansionPathname Expansion

Proprio come un commento, è probabile che un'espansione a due passaggi in puro bash sia ancora più rapida rispetto al tentativo di fare la stessa cosa invocando un programma esterno, quindi non me ne preoccuperei troppo.


Grazie, controllerò il link. La mia preoccupazione è che devo fare questo lavoro più di una volta nell'intero script, quindi la mia unica preoccupazione era di avere lo stesso codice ripetuto più volte compromettendo la leggibilità. Ad ogni modo sto inventando una soluzione educata che pubblicherò. Saluti
neurino,

È possibile inserire quel codice in una funzione per evitare la ripetizione del codice.
jw013,

È quello che sto facendo ma, come sai, le funzioni bash non possono restituire le stringhe ... o, almeno, era quello che pensavo prima di 10 minuti fa :)
neurino

4
Ecco alcuni esempi di cose da fare e da non fare - Bash Extended Globbing .. Per l'esempio precedente, sarebbe:shopt -s extglob; t="${t//+([^A-Za-z0-9])/-}"
Peter.O

1
@fered: grazie, molto interessante, lo controllerò. L'URL del tuo link ha un carattere aggiuntivo e restituisce un 404, quello funzionante è Bash Extended Globbing
neurino
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.