bash error bad substitution

Bash Bad Substitution Syntax Error: Simple and Quick Fixes

Sometimes while writing a Bash script I have seen the Bad substitution syntax error and looking at forums I realised that I’m not alone, other people are seeing the same error too.

What is the Bash bad substitution error?

It’s a syntax error that occurs when you execute your Bash script and it can be caused by different reasons. Two common causes for this error are the incorrect use of command substitution and incorrect characters added to the lines of your script (for example extra dollar signs or white spaces).

We will go through some examples of scripts in which this error occurs, in this way you will know how to fix the bad substitution error when you see it in your scripts.

At the end of this guide I also have a nice exercise for you to test your knowledge.

Let’s get started!

Bad Substitution Error Related to Command Substitution

One circumstance in which this error occurs is when you want to use command substitution but by mistake you use curly braces instead of parentheses.

Command substitution allows to store the output of a Bash command (as complex as you want) into a variable. It allows to build very flexible and powerful Bash scripts.

I have created a very simple script to show you how the bad substitution error occurs with an incorrect use of command substitution.

I want to use command substitution to store the output of the command ls -al in the variable OUTPUT.

#!/bin/bash

OUTPUT=${ls -al}
echo "$OUTPUT"

When I execute the script I see the following output:

(localhost)$ ./subst.sh
./subst.sh: line 3: ${ls -al}: bad substitution

What’s wrong with my script?

According to the error there’s something wrong at line 3 of the script, I have used the wrong type of brackets…..

I have used ${ } around the ls command, instead command substitution requires $( ) around the command.

Let’s replace the parentheses with curly brackets and then rerun the script:

#!/bin/bash

OUTPUT=$(ls -al)
echo "$OUTPUT"

Now the output is:

(localhost)$ ./subst.sh
total 8
drwxr-xr-x   4 myuser  mygroup  128 Jul 26 12:57 .
drwxr-xr-x  29 myuser  mygroup  928 Jul 26 12:54 ..
-rwxr-xr-x   1 myuser  mygroup   45 Jul 26 12:56 subst.sh
-rw-r--r--   1 myuser  mygroup    0 Jul 26 12:55 testfile

This time the script works well, we have fixed the bad substitution error.

Let’s look at other reasons for the same syntax error…

Bad Substituion Error Caused by White Spaces

The cause of this error can also be the presence of white spaces in our code that go against Bash syntax. These white spaces cause syntax errors in the way I will show you below…

I have modified the last line of the script we have created in the previous section:

#!/bin/bash

OUTPUT=$(ls -al)
echo "${OUTPUT }"

I have added curly brackers around the OUTPUT variable and by mistake I have added a white space before closing the curly bracket.

When I run the script I get the following error from the Linux shell:

(localhost)$ ./subst.sh
./subst.sh: line 4: ${OUTPUT }: bad substitution

The error message clearly tells the line that is causing the error.

To solve the problem we can just remove the white space before the closing curly brackets.

Make sure you verify any incorrect white spaces in your code if you get the bad substitution error.

Dollar Sign Used Twice When Printing the Value of a Variable

Another common cause for this error is using the dollar sign twice when you print the value of a variable in your script.

Here is the script used previously, but modified to introduce a syntax error in the last line:

#!/bin/sh

OUTPUT=$(ls -al)
echo "${$OUTPUT}"

As you can see I have used the $ sign twice in the line where I use the echo command.

The error from the script is:

(localhost)$ ./subst.sh
./subst.sh: line 4: ${$OUTPUT}: bad substitution

The solution is to remove the extra $ sign inside the curly brackets.

Let’s see what happens if we have multiple variables of type string in our echo command…

Bad Substitution Error and String Variables

In the next script we will print in the shell the full path of a directory created from the concatenation of three different variables: BASE_DIR, APP_DIR and CONF_DIR.

#!/bin/bash

BASE_DIR=/opt/base
APP_DIR=app
CONF_DIR=conf
echo ${$BASE_DIR/$APP_DIR/$CONF_DIR}

The code looks correct, let’s run it!

(localhost)$ ./full_path.sh
./full_path.sh: line 6: ${$BASE_DIR/$APP_DIR/$CONF_DIR}: bad substitution

What’s causing the bad substitution error?

We are seeing a similar error to the one in the previous section, caused by an extra dollar sign that the Bash shell doesn’t like.

The difference between this script and the previous one is that in the previous script we only had one variable within curly brackets.

Let’s see how we can fix the error in this script…

Option 1: Remove the outer $ sign in the last line:

#!/bin/bash

BASE_DIR=/opt/base
APP_DIR=app
CONF_DIR=conf
echo $BASE_DIR/$APP_DIR/$CONF_DIR

If I run the script the output is:

(localhost)$ ./full_path.sh
/opt/base/app/conf

The script works well!

Option 2: We will keep the outer $ sign and remove the dollar sign immediately before the BASE_DIR variable:

#!/bin/bash

BASE_DIR=/opt/base
APP_DIR=app
CONF_DIR=conf
echo ${BASE_DIR/$APP_DIR/$CONF_DIR}

This time the scripts prints in the shell…

(localhost)$ ./full_path.sh
/opt/base

The output is incorrect, the values of APP_DIR and CONF_DIR are missing.

Here is another possible option:

#!/bin/bash

BASE_DIR=/opt/base
APP_DIR=app
CONF_DIR=conf
echo ${BASE_DIR}/${APP_DIR}/${CONF_DIR}

And the output is correct:

(localhost)$ ./full_path.sh
/opt/base/app/conf

I definitely prefer this version because the three variables are clearly separated and this helps us avoid errors in the script.

Bash Bad Substitution When Converting String Variables to Uppercase or Lowercase

Converting strings in your Bash script from lowercase to uppercase (or viceversa) is a common requirement.

Recent versions of Bash (e.g. here I’m using Bash 4.4.19) provide a built-in way for uppercasing and lowercasing strings.

Here’s how…

[myuser@localhost ~]$ DAY=monday
[myuser@localhost ~]$ echo ${DAY}
monday
[myuser@localhost ~]$ echo ${DAY^}
Monday
[myuser@localhost ~]$ echo ${DAY^^}
MONDAY

A similar syntax but with , instead of ^ allows to convert strings from uppercase to lowercase:

[myuser@localhost ~]$ DAY=MONDAY
[myuser@localhost ~]$ echo ${DAY}
MONDAY
[myuser@localhost ~]$ echo ${DAY,}
mONDAY
[myuser@localhost ~]$ echo ${DAY,,}
monday

Now let’s try to run this with an earlier version of Bash. Before I was running it on Linux, now let’s try with the Bash shell on Mac:

(localhost)$ bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)
Copyright (C) 2007 Free Software Foundation, Inc.

Here is the error I get when I try to convert the string variable to uppercase:

(localhost)$ DAY=monday
(localhost)$ echo ${DAY}
monday
(localhost)$ echo ${DAY^}
-bash: ${DAY^}: bad substitution
(localhost)$ echo ${DAY^^}
-bash: ${DAY^^}: bad substitution

In both cases we receive a “bad substitution” error because this version of the Bash shell doesn’t support this syntax.

So, how can I convert this string into uppercase?

The alternative with this version of Bash is using the tr command:

(localhost)$ DAY=monday
(localhost)$ echo "$DAY" |  tr '[:lower:]' '[:upper:]'
MONDAY

Makes sense?

Fix the Bad Substitution Error: A Simple Exercise

We are almost at the end of this guide and to make sure you now know how to fix the bad substitution error, I want to give you a simple exercise.

I have created a small script called archive.sh that creates a tar archive of the files in the current directory.

#!/bin/bash

ARCHIVE_NAME=archive.tar.gz
tar cvzf ${$ARCHIVE_NAME} .

if [ $? -eq 0 ]; then
    ARCHIVE_SIZE=${ls -al archive.tar.gz | awk '{print $5}'}
    echo "Archive created successfully. The size of the archive is $ARCHIVE_SIZE"
fi

But something doesn’t go well when I run it:

[myuser@localhost]$ ./archive.sh
./archive.sh: line 4: ${$ARCHIVE_NAME}: bad substitution

Can you see what is causing the error?

Try to fix the script and rerun it to make sure the bad substitution error disappears.

Also, have a look at this guide about the tar command if you want to learn more about it.

Conclusion

In this guide I have explained the most common causes for the Bash bad substitution syntax error and you now have different ways to understand why this error occurs and to fix it.

This error could be due to:

  • Incorrect ways of using command substitution.
  • Unexpected white spaces within commands.
  • Too many dollar signs when referring to variables.
  • A Bash version that don’t support specific features like lowercasing and uppercasing.

Does the error you are seeing in your script fit one of the scenarios above?

Let me know which one if it does, and if it doesn’t let me know about the error you are seeing in the comments below 🙂


Related FREE Course: Decipher Bash Scripting

One comment

Leave a Reply

Your email address will not be published. Required fields are marked *