3

Given the string foo-bar, what is a good way to convert it to Foo Bar?

Using Bash, OSX.

B Seven
  • 7,659
  • 7
  • 23
  • 20

6 Answers6

5

Start by changing dashes to spaces, like: sed 's/-/ /g'

Uppercasing the first letter is already solved (go upvote them; or just mark this question a duplicate of that one).

Then combine them: sed -e 's/-/ /g' -e 's/\b\(.\)/\u\1/g'

$ echo "foo-bar-baz-nonce" | sed -e 's/-/ /g' -e 's/\b\(.\)/\u\1/g'
Foo Bar Baz Nonce
$ 
  • This is what I was looking for. How can I use it in a function to operate on $1: `function format { sed -e 's/-/ /g' -e 's/\b\(.\)/\u\1/g' }` – B Seven Dec 09 '14 at 02:01
  • This is not portable syntax - I think even the OSX version of `sed` will have difficulties w/ `\b` - I could be wrong about that though. – mikeserv Dec 09 '14 at 04:49
  • 3
    Apparently this doesn't work on OSX. I get `foo uar uaz nonce`. – B Seven Dec 09 '14 at 10:51
  • On OSX, look into installing `gsed` and using that instead. Works perfectly. – Jack Kinsella Aug 23 '22 at 16:42
2

One solution using , not restricted to only `foo-bar`

$ cat file
aaa-zzz-eee-rrr
foo-bar

code

$ perl -ne 'print join " ", map { ucfirst } split /-/' file
Aaa Zzz Eee Rrr
Foo Bar

Another solution using pure bash

while IFS='-' read -r -a words; do
    printf '%s\n' "${words[@]^}" | paste -sd ' '
done < file

Output:

Aaa Zzz Eee Rrr 
Foo Bar
Gilles Quénot
  • 31,569
  • 7
  • 64
  • 82
2

For the splitting in a POSIX shell you could do:

set -f; IFS=-; set -- $1; IFS=' '

There - now all of your dashes are spaces and you can have the entire string in "$*" or else each space - previously dash - separated string in $1 $2 $3 ... (the total count of which is available to you in "$#") or you can get them as an expandable argument list in "$@".

Now, for the case conversion you can do:

IFS='
'; for c in $(printf %.1s "$@" | dd cbs=1 conv=unblock,ucase)
do set -- "$@" "$c${1#[!"$IFS"]}"; shift; done

Here's the whole thing by example:

set -f -- aaa-zzz-eee-rrr-foo-bar
IFS=-; set -- $1; IFS=' 
'; for c in $(printf %.1s "$@" | dd cbs=1 conv=unblock,ucase)
do set -- "$@" "$c${1#?}"
shift; done; printf %s\\n "$@"

which prints:

Aaa
Zzz
Eee
Rrr
Foo
Bar

...which isn't space-separated I know - I used "$@". It is space-separated in "$*" because I set $IFS's first byte to space - the delimiter is definable in that way. For example:

IFS=k; printf %s\\n "$*"; IFS=' '; printf %s\\n "$*"

...which prints...

AaakZzzkEeekRrrkFookBar
Aaa Zzz Eee Rrr Foo Bar

You can save it any time of course:

IFS=-; dashes="$*"; IFS=' '; spaces="$*"; IFS=; empty="$*"
printf %s\\n "$dashes" "$spaces" "$empty"

...which prints:

Aaa-Zzz-Eee-Rrr-Foo-Bar
Aaa Zzz Eee Rrr Foo Bar
AaaZzzEeeRrrFooBar

This is a more complex subject but it can be used to great effect in these areas. It is important to protect data integrity though - use set -f when splitting in the shell to avoid filename generation on [?* and quote expansions you don't intend to split.

The dd command above - as it should be noted - is likely only to be very effective in an ASCII locale. In others you should probably look to recode or iconv or similar.

mikeserv
  • 57,448
  • 9
  • 113
  • 229
1

Step 1: Replace the - with a space

For this you can use tr command as follows:

tr "-" " "

Step 2: Make first letter of every word capital

For this, you can find the word boundary using \b and make immediate letter capital. The . represents immediate letter after word boundary \b, \U makes it capital and & will keep all other letters in the letters as they were.

sed -e 's/\b./\U&/g'

Check:

echo "foo-bar-foo-bar" | tr "-" " " | sed -e 's/\b./\U&/g'
Foo Bar Foo Bar
Mandar Shinde
  • 3,156
  • 11
  • 39
  • 58
0

If that string is part of a file or output:

sed 's/foo-bar/Foo Bar/g' file

Assuming there are no "strange" characters in the string (/, \, &):

string="foo-bar"
set -- $(echo "${string//-/ }")
replstr="$(for word in $*; do echo -n "${word^} "; done)"
replstr="${replstr% }"
sed "s/${string}/${replstr}/g' file
Hauke Laging
  • 88,146
  • 18
  • 125
  • 174
0

in bash

v=foo-bar && v=$(IFS=- read -ra x <<<"$v"; printf '%s' "${x[*]^}") && printf '%s\n' "$v"
Foo Bar

In python

v=foo-bar python -c 'import os, string
print string.capwords(" ".join(os.environ["v"].split("-")))
'
Foo Bar
iruvar
  • 16,515
  • 8
  • 49
  • 81