In bash, what does `declare -i n` change about later assignments to `n`, and what happens if you then assign a non-numeric value to it?
answer
- it marks the name, not the value
- assignments get evaluated, not stored
- a bare word is a variable, and unset means zero
- declare -p shows what is attached
- +i takes it off again, -r never comes off
basics
~20 sdeclare -i n attaches the integer attribute to the name n, so every later assignment evaluates its right-hand side as an arithmetic expression. n=2+3 stores 5, and a bare non-numeric word is treated as a variable name that evaluates to 0.
solid answer
~40 s`declare -i` sets an *attribute* on the name, not a one-off conversion of the current value. From then on, any assignment to `n` has its right-hand side evaluated in arithmetic context, so `n=2+3` stores `5` and `n=n+1` increments without needing `$` or `$(( ))`. The surprise is what happens with non-numeric input: in arithmetic context a bare word is read as a variable name, so `n=foo` with `foo` unset silently stores `0` rather than failing. A malformed expression such as `n=3x` is an arithmetic error — the assignment does not happen and the command returns non-zero, which under `set -e` aborts the script. Attributes stick to the name until you remove them with `declare +i n`, and `declare -p n` prints the name with its current attributes so you can see what is set.
code
bash · 17 lines#!/usr/bin/env bash
declare -i n
n=2+3
echo "n=$n" # n=5
n=n*2
echo "n=$n" # n=10
n=foo # foo is unset -> arithmetic value 0
echo "n=$n" # n=0
declare -p n # declare -i n="0"
declare +i n # drop the integer attribute
n=2+3
echo "n=$n" # n=2+3go deeper
Know that declare attaches attributes to a variable name and that -i means later assignments are treated as arithmetic, so n=2+3 stores 5 rather than the text.
Explain that the attribute lives on the name and governs future assignments, and walk through what a non-numeric value does: a bare word is a variable reference that evaluates to 0, while a malformed expression fails the assignment with a non-zero status.
Point out the operational risk — silent zeros from unvalidated input feeding counters, timeouts or indices — and argue for explicit validation plus visible arithmetic at the point of use rather than an attribute set far away in the file.
Decide the house position on attributes: which of -i, -r, -a, -A are worth their readability cost, and how a shared shell library declares constants so that being sourced twice is not an error.
## Attributes belong to the name Bash variables are strings by default. `declare` (and its synonym `typeset`) lets you attach *attributes* to a name, and those attributes then govern how future assignments to that name behave. This is the key mental model: `declare -i n` does not convert the value that `n` holds right now into an integer type — it marks the name so that everything assigned to it from that point on is put through arithmetic evaluation first. ```bash declare -i n n=2+3 echo "$n" # 5 n=n+1 # no $ needed: bare names are read as variables in arithmetic echo "$n" # 6 ``` Without the attribute, `n=2+3` stores the literal three-character string `2+3`. With it, the right-hand side is evaluated the way an arithmetic context evaluates anything, and the *result* is stored. ## The non-numeric case, precisely This is the part interviewers probe, because the behaviour is surprising and silent: ```bash declare -i n n=foo # foo is an unset variable name -> evaluates to 0 echo "$n" # 0 ``` In arithmetic context a bare identifier is not a literal string; it is a variable reference. `foo` is unset, an unset variable evaluates to 0, and so `n` gets 0. No error, no warning. If a script uses `declare -i` on a variable that receives user input or a value parsed out of a file, garbage silently becomes zero — and a zero can be far more dangerous than an obvious failure when it feeds a `sleep`, a retry count, or an index. A value that is not even a valid expression behaves differently: ```bash declare -i n n=3x # arithmetic syntax error; assignment fails, status non-zero ``` Here bash reports an arithmetic error, `n` keeps its previous value, and the assignment command exits non-zero. Under `set -e` that terminates the script. So `declare -i` gives you two distinct failure modes for bad input: silent zero for a bare word, hard failure for a malformed expression. Neither is validation. If a value must be a number, check it explicitly with a pattern test before you trust it. ## Reading attributes back `declare -p` prints a variable's declaration, attributes included, which is the fastest way to find out what is going on with a name: ```bash declare -ir MAX=100 declare -p MAX # declare -ir MAX="100" ``` The letters after the dash are the attributes. Attributes combine freely: `-i` integer, `-r` readonly, `-x` marked for export, `-a` indexed array, `-A` associative array, `-l` and `-u` for automatic lower/upper casing on assignment. `declare -p` with no name lists everything. ## Removing an attribute Most attributes are removed with a `+` instead of a `-`: ```bash declare -i n declare +i n # n is a plain string variable again ``` The important exception is `-r`. Once a name is readonly — whether via `declare -r` or `readonly` — you cannot clear the attribute, reassign the variable, or `unset` it for the remaining life of that shell. That is not a limitation to work around; it is the point of the attribute. It does, however, have a real practical consequence: a shell library that does `readonly VERSION=1.2` at the top will fail with a readonly-variable error the second time it is sourced into the same shell, so libraries that may be loaded more than once need to guard such declarations rather than declaring unconditionally. ## When to reach for `-i` Honestly, not often. The integer attribute saves a little typing in counters, but the mainstream way to do arithmetic in bash is an explicit arithmetic expression at the point of use, which is visible in the code rather than hidden in a declaration made fifty lines earlier. A reader who has not seen the `declare -i` line cannot explain why `n=2+3` produced 5. The attributes that earn their place in production scripts are `-r` for constants you want protected, and `-a` or `-A` when you need the array shapes. Treat `-i` as something you must be able to *read*, since you will meet it in other people's scripts, more than something you must reach for.
- How do you see which attributes a variable currently has?`declare -p NAME` prints the variable as a declaration, with its attribute letters after the dash — for example `declare -ir MAX="100"` shows both the integer and readonly attributes. With no name, `declare -p` dumps every variable in the shell. It is the fastest way to answer "why is this name behaving oddly".
- What does `declare -r` add, and can you take it back?It makes the name readonly: further assignments fail and `unset` refuses. Unlike the other attributes there is no `declare +r` — the name stays readonly for the life of the shell. The practical consequence is that a library doing `readonly VERSION=...` at top level errors the second time it is sourced into the same shell, so such declarations need a guard.
- If a variable must hold a number, is `declare -i` enough validation?No. A bare non-numeric word is treated as an unset variable name and silently becomes 0, so invalid input is converted rather than rejected. Validate explicitly — for example a pattern test that the value consists only of digits — and fail with a clear message. Use the attribute for convenience, never as an input guard.
saying these in an interview costs you the question
- Says declare -i converts the value once, like a cast
- Expects n=foo to raise an error
- Thinks the attribute follows the value into another variable
- Believes declare +r removes the readonly attribute
- Treats declare -i as input validation for numbers