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 identifierFix
#!/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.