6

I am trying to only change the first letter of a string to lowercase using a Shell script. Ideally a simple way to go from CamelCase to lowerCamelCase.

GOAL:

$DIR="SomeString"
# missing step
$echo $DIR
someString

I have found some great resources for doing this to the entire string but not just altering the first letter and leaving the remaining string untouched.

haysclark
  • 1,080
  • 8
  • 16

6 Answers6

6

If your shell is recent enough, you can use the following parameter expansion:

DIR="SomeString"   # Note the missing dollar sign.
echo ${DIR,}
choroba
  • 231,213
  • 25
  • 204
  • 289
  • I'm using OSX and it looks like the default Bash is not very recent. I get errors when I try and of the Bash v4 features: bash: ${DIR,}: bad substitution – haysclark Sep 04 '14 at 21:52
  • @Infinite time to look at [macports.org](http://www.macports.org). You can get many good GNU tools in addition to OSX's BSD tools. – clt60 Sep 04 '14 at 21:56
  • @jm666 Thanks :D I am well aware of MacPorts and Brew. This is for a build script that needs to run on a variety of platforms and it is outside out main build scripts which use Rake. – haysclark Sep 04 '14 at 22:03
4

Alternative solution (will work on old bash too)

DIR="SomeString"
echo $(echo ${DIR:0:1} | tr "[A-Z]" "[a-z]")${DIR:1}

prints

someString

for assing to variable

DIR2="$(echo ${DIR:0:1} | tr "[A-Z]" "[a-z]")${DIR:1}"
echo $DIR2

prints

someString

alternative perl

DIR3=$(echo SomeString | perl -ple 's/(.)/\l$1/')
DIR3=$(echo SomeString | perl -nle 'print lcfirst')
DIR3=$(echo "$DIR"     | perl -ple 's/.*/lcfirst/e'

some terrible solutions;

DIR4=$(echo "$DIR" | sed 's/^\(.\).*/\1/' | tr "[A-Z]" "[a-z]")$(echo "$DIR" | sed 's/^.//')
DIR5=$(echo "$DIR" | cut -c1 | tr '[[:upper:]]' '[[:lower:]]')$(echo "$DIR" | cut -c2-)

All the above is tested with OSX's /bin/bash.

clt60
  • 62,119
  • 17
  • 107
  • 194
3

With sed:

var="SomeString"
echo $var | sed 's/^./\L&/'

^ means the start of the line \L is the command to make the match in lowercase & is the whole match

Casimir et Hippolyte
  • 88,009
  • 5
  • 94
  • 125
  • Thanks for the quick solution, sadly I am using POSIX sed so I don't have access to \L. – haysclark Sep 04 '14 at 21:50
  • Take a look at your `sed` manpage and at your `re_format` manpage. Sometimes if you use `-E` in `sed`, it will use the _expanded regular expressions_ which may or may not include `\L`. You may also see other parameters that can be passed to `sed` that can expand its regular expression ability. – David W. Sep 04 '14 at 22:14
  • You actually can do this on mac if you use homebrew: https://www.topbug.net/blog/2013/04/14/install-and-use-gnu-command-line-tools-in-mac-os-x/ – spinlock May 21 '15 at 23:53
2

Perl solution:

DIR=SomeString
perl -le 'print lcfirst shift' "$DIR"
choroba
  • 231,213
  • 25
  • 204
  • 289
2

Since awk hasn't yet been mentioned, here's another way you could do it (requires GNU awk):

dir="SomeString"
new_dir=$(awk 'BEGIN{FS=OFS=""}{$1=tolower($1)}1' <<<"$dir")

This sets the input and output field separators to an empty string, so each character is a field. The tolower function does what you think it does. 1 at the end prints the line. If your shell doesn't support <<< you can do echo "$dir" | awk ... instead.

Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
-1

If you are looking for a POSIX compliant solution then have a look at typeset.

var='SomeString'
typeset -lL1 b="$var"
echo "${b}${var#?}"

Output:

someString

The typeset command creates a special variable that is lowercase, left aligned and one char long. ${var#?} trims the first occurrence of pattern from the start of $var and ? matches a single character.

jaypal singh
  • 74,723
  • 23
  • 102
  • 147