Bash error: "cannot assign to non-variable"

Fix "cannot assign to non-variable" when Bash sees an assignment target that is not a simple variable name, such as a command substitution or literal.

Error String

bash: cannot assign to non-variable

Tldr

This error means the left-hand side of an assignment is not a valid variable name. Common causes: spaces around `=`, assigning to a command substitution like `$(cmd)=value`, or using `export`/`local` with a complex expression.

Cause

Bash assignments must have a simple variable name on the left. Writing `foo = bar` (with spaces) makes Bash treat `foo` as a command and `=` as an argument. Writing `$(cmd)=value` tries to assign to dynamic output. Writing `export "VAR=VALUE"` also fails because export expects a name, not a quoted assignment string.

Repro

#!/usr/bin/env bash
foo = bar          # foo: command not found (or cannot assign)
$(cmd)=value       # cannot assign to non-variable
export "X=1"       # not a valid identifier

Fix

#!/usr/bin/env bash
foo=bar            # no spaces
VAR=value; export VAR
# or:
export VAR=value

# Dynamic names need indirect expansion (Bash 4.3+):
name=MY_VAR
declare "$name=value"

Explanation

In Bash, `name=value` is an assignment only when there are no spaces around `=`. `export` and `local` accept either `export name=value` or `export name` after `name=value`. For dynamic variable names, use `declare` or `printf -v`, not assignment syntax.

Faq

Q

Why does `export "X=1"` fail?

A

export treats a quoted string as a single argument and expects it to be a valid identifier. Use `export X=1` (unquoted) or `X=1; export X`.

Q

How do I set a variable with a dynamic name?

A

Use `declare "name=value"` or `printf -v name "%s" value` in Bash 4.3+.

Q

Why do other languages allow spaces around =?

A

The shell parses a command line, so whitespace separates words; an assignment is recognised only as one unbroken word.

Q

How do I set a variable whose name is in another variable?

A

Use `declare "$key=$value"` (or `declare -n` namerefs in Bash 4.3+) instead of `eval`.

Deep Dive

Heading

Spaces around = are the usual cause

Body

Shell assignment must have no whitespace: `name=value`. With spaces, `name = value` is parsed as running the command `name` with arguments `=` and `value`, and depending on context you get "command not found" or this assignment complaint. The same applies to arithmetic-looking assignments outside `(( ))` — use `(( n = n + 1 ))` or `n=$((n + 1))`, never `n = $((n+1))`.

Heading

Assigning to something that is not a name

Body

The message also appears when the left-hand side is an expression rather than an identifier: `$name=value` (which expands the variable first), `2var=x` (names cannot start with a digit), or a name containing a dash. Variable names may use letters, digits and underscores and must not start with a digit. For indirect assignment use `declare "$key=$value"` or a nameref (`declare -n ref=$key`), both of which take the name from a variable safely.

Checklist

Remove any whitespace around `=`.

Do not prefix the left-hand side with `$`.

Check the name starts with a letter or underscore.

Use `declare "$name=$value"` or a nameref for indirect assignment.