10

I'm trying to change uppercase to lowercase using string replacement in bash, but i'm getting a bad substitution error.

> a=HEY
> echo $a 
HEY 
> echo ${a,,}
-bash: ${a,,}: bad substitution
# desired output is hey

I've seen similar questions to this, but in most cases it was down to using an earlier version of bash. I'm using GNU bash 4 and still having the same problems.

> bash --version
GNU bash, version 4.3.33(1)-release (x86_64-apple-darwin14.1.0)

This is a Mac thing maybe? Any help would be appreciated.

A-K
  • 147
  • 1
  • 1
  • 9
  • Not providing a pattern at the end is a shortcut for doing `${a,,?}`. What happens if you try `${a,,?}` explicitly? – dg99 Apr 24 '15 at 19:16
  • `GNU bash, version 4.3.33` - `$ ( a=HEY; echo ${a,,} )` yields `hey` without a problem? – David C. Rankin Apr 24 '15 at 19:20
  • Are you sure your current shell is bash 4? Maybe your session runs in OS X default bash 3? Try `echo $BASH_VERSION`. – baf Apr 24 '15 at 19:21
  • @baf That's got to be it. I just tested with `3.2.39` and got `-bash: ${a,,}: bad substitution`. It looks like OP may have bash 4 installed, but has a bash 3 (or other) shell running. – David C. Rankin Apr 24 '15 at 19:25
  • @baf yes! you're right. echo $BASH_VERSION 3.2.57(1)-release Cheers! – A-K Apr 24 '15 at 19:26
  • This might be obvious, If you have installed using homebrew it will install bash 4 in /usr/local/bin/bash AFAIK so usually opening a new command window will run bash 4 but if you put '#!/bin/bash' in a script it will find the system bash 3. Best to use '#!/usr/bin/env bash' to get the correct version. To get the version from the current shell use echo `$BASH_VERSION`. –  Apr 26 '15 at 05:20
  • @lokulin not so obvious to me :) thanks for the info – A-K Apr 26 '15 at 12:40
  • 1
    work-a-round: `echo $a | tr '[:upper:]' '[:lower:]'` ? – kecso May 12 '15 at 04:59
  • @kecso good suggestion, however I'd say it's not a workaround since `tr` is there to do exactly that kind of transform (among others). – Adam T May 21 '15 at 20:40

2 Answers2

9

Looks like the bash that is first in PATH happens to be 4.3.33, but the bash you're running in the interactive session is probably an older version. Run echo "$BASH_VERSION" to check.

If the above is correct, run

type bash

to see the path of the newer version, probably something like /opt/local/bin/bash. I'll assume it is. If you want that to be your login shell, first add it to /etc/shells

sudo -e /etc/shells

After that, users are allowed to select that as their login shell by using the chsh (change shell) command

chsh -s /opt/local/bin/bash
geirha
  • 5,801
  • 1
  • 30
  • 35
  • I'm on a company computer. Therefore, I can't upgrade bash. Does anyone know an alternative for lowercase conversion? – Andrew Kirna Sep 03 '18 at 22:36
  • 2
    `awk '{print tolower($0)}' <<< "$var"` or `tr '[:upper:]' '[:lower:'] <<< "$var"` though if you have GNU tr, it only handles conversion of ascii letters, while BSD tr handles utf-8, so if you're on MacOS, use the tr. If you're on GNU/linux, use the awk. – geirha Sep 04 '18 at 05:35
  • sweet thanks. awk is a useful tool I feel most people don’t know about. – Andrew Kirna Sep 06 '18 at 23:48
  • Same problem in WSL, debian running under windows. bash 4.4.20, but 'echo "$BASH_VERSION"' is empty and the string replacements don't work – andrew lorien Jul 21 '21 at 08:23
  • 1
    @andrewlorien use `adduser` instead of `useradd` to create a user; the defaults of `adduser` gives the user a homedir and bash as login shell, while the defaults of `useradd` gives the user sh as login shell and no homedir. – geirha Jul 22 '21 at 11:59
2

Based on the comments on my comment, this is the answer:

echo $a | tr '[:upper:]' '[:lower:]'
kecso
  • 2,387
  • 2
  • 18
  • 29
  • 1
    Thanks kecso, tr is always a good workaround. My question was really about why string replacement wasn't working though, rather than trying to get the same result by a different means. – A-K Jun 12 '15 at 13:40