I'm replacing, from a feed title, all chars except letters and digits with a dash to use the result as a safe filename for any filesystem:

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

However I'd like to condense all repeating dashes with a single one like Episodie-06-No-hope-of-riding-home-NEW-Advanced-grammar

I found I can achieve it using a two pass substitution:

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

I thought I could do it in a single pass like:

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

but it doesn't work.

Any clue?

Note: I don't want to go with sed or other tools


You need something more powerful than traditional shell wildcards. In bash, set the extglob option, which gives you access to regular expressions in glob patterns through an unusual syntax inherited from ksh.

shopt -s extglob
  • Thanks, there was a comment from fered under jw013 answer with this solution. Some info on compatibility with other shells of this syntax? I'm not concerned about it that much, just to know more about shopt and which shells support it. – neurino Nov 1 '11 at 11:41
  • @neurino shopt is specific to bash. The pattern syntax that it enables is always available in all ksh variants. In zsh, this syntax must be enabled with setopt ksh_glob. POSIX has no such feature, its wildcards are less powerful than regexps. Shells other than bash/ksh/zsh, which in practice mostly means ash nowadays, tend to stick to POSIX wildcards. – Gilles 'SO- stop being evil' Nov 1 '11 at 13:53
  • well, at this point I prefer more compatibility and flexibility with a bit more overhead: echo "$t" | sed -r 's/[^[:alnum:]]+/-/g; s/^-|-$//'. I accept your answer as it exactly do what asked in question. – neurino Nov 1 '11 at 20:44
  • @neurino If you want portability to other shells, then you can go with glenn jackman's answer. By the way, note that the ${var/PATTERN/REPLACEMENT} construct is also specific to ksh/bash/zsh. – Gilles 'SO- stop being evil' Nov 1 '11 at 21:07
  • I prefer sed as I know better its syntax and behavior, I can easily add a statement to remove starting/trailing dashes, I don't need to care about \n char. Is sed way less available than tr? – neurino Nov 1 '11 at 21:12

tr is a good tool for this job

new=$( printf "%s" "$t" | tr -cs 'a-zA-Z0-9' '-' )
new=${new#-}; new=${new%-}
  • Thank you, +1, I never recall about tr... However I was trying to get it done in Bash, otherwise I'd go with sed: echo "$t" | sed -r 's/[^A-Za-z0-9]+/-/g' – neurino Oct 31 '11 at 18:07
  • Down voted because it conflicts with Note: I don't want to go with sed or other tools – Paul Calabro May 24 '18 at 21:41

If you want to stay with pure bash, you'll have to settle for the two-pass solution. Bash string substitutions use globs, as in pathname expansion, and not regular expressions. The only special characters in globs are *, ?, and [], whose rough equivalents in regular expressions are .*, ., and []. Take a look at the Wooledge wiki and the bash(1) man page sections on Parameter Expansion and Pathname Expansion for more info.

Just as a comment, a two-pass expansion in pure bash is still likely to be faster than trying to do the same thing by invoking an external program, so I wouldn't worry about it too much.

  • Thanks, I'll check the link. My worry is I have to do this work more than once in the whole script so my only concern was about having the same code repeated over and over compromising readability. Anyway I'm coming up with a polite solution I'm going to post. Cheers – neurino Oct 30 '11 at 23:34
  • You could put that code in a function to avoid repeating code. – jw013 Oct 30 '11 at 23:38
  • It's what I'm doing but, as you know, bash functions cannot return strings... or, at least, it was what I thought before 10 minutes ago :) – neurino Oct 30 '11 at 23:48
  • 4
    Here are some examples with do-s and-don't-s -- Bash Extended Globbing .. For the above example, it would be: shopt -s extglob; t="${t//+([^A-Za-z0-9])/-}" – Peter.O Oct 31 '11 at 2:19
  • 1
    @fered: thank you, very interesting, I'll check it out. Your link url has an extra char and returns a 404, the working one is Bash Extended Globbing – neurino Oct 31 '11 at 9:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.