As a Bash scripting language built into virtually every Linux machine, Bash provides the foundation for developers to create automated scripts for system administration, DevOps, and application deployment. According to the Stack Overflow Developer Survey, Bash ranks in the top 10 most popular technologies among developers. However, Bash lacks some more advanced features for writing robust and complex scripts. This is where the declare command comes in – unlocking functionality in Bash to take your scripting to the next level.
In this comprehensive guide, we‘ll cover everything you need to know about declare from an expert perspective, including detailed examples and comparisons to other languages. Let‘s dive in!
An Introduction to Declare Basics
The declare command enables declaration of variables with specific attributes in Bash. The basic syntax is:
declare [options] [name[=value]]
For example:
declare myvar="Hello"
declare -i myint=5
Declare is bash built-in, meaning no external libraries or tools needed. Key things declare allows:
- Setting variable types like integers, arrays and functions
- Controlling scope and export behavior
- Enforcing case formatting on names
- Making constants and read-only values
Experienced developers will notice similarities to strict type declaration in languages like C, Go, and Rust. But how widely is Bash actually used in the real world?
The Popularity of Bash Scripting in Stats
Bash and the Linux shell underpins automation across servers, cloud infrastructure, CI/CD pipelines, and more. Consider these Bash usage statistics:
- Over 50% of developers use Bash according to StackOverflow with growth outpacing other scripting languages
- Bash/Shell is the #1 most in-demand scripting skill on job sites like LinkedIn
- 100% of Fortune 500 companies use Linux servers with Bash as the default shell
- Common applications like Nginx, Docker, Kubernetes, Ansible and Terraform are all configured via Bash
Source: Developer Economics State of the Developer Nation Q2 2019
So millions of developers rely on Bash daily. Adopting declare allows writing more robust Bash automation scripts for the cloud and system administration.
Setting Variable Types
Like a loosely typed language, variables in Bash by default have no type. Values like "10" and "foo" can be assigned to the same variable. Declare fixes this by enabling type enforcement:
Integers
The -i flag sets a numeric integer type:
declare -i myint=5
Now attempting to assign a non-integer string will display an error:
myint="hello"
bash: hello: invalid integer
This also works for arithmetic:
declare -i x=5+4
echo $x # 9
So -i ensures numeric variable behavior.
Arrays
Arrays contain ordered, indexed values and are defined in Bash with -a:
declare -a myarray=(1 2 3)
Accessing elements uses index notation:
myarray[0] # 1
We can iterate over array contents with:
for i in "${myarray[@]}"; do
echo $i
done
# 1
# 2
# 3
This provides an ordered data structure in Bash.
Associative Arrays
Associative arrays, also known as maps or dictionaries, store key-value pairings:
declare -A prices
prices[apples]=2
prices[oranges]=3
Elements are accessed by key name rather than numeric index:
prices[apples] # 2
This works nicely for lookup tables:
users[john]="John Smith"
users[jane]="Jane Doe"
echo "Username: ${users[john]}"
# Username: John Smith
Dictionaries are very useful in scripting.
Functions
We can declare functions using -f:
declare -f myfunc(){
echo "Running myfunc"
}
myfunc # "Running myfunc"
This declares myfunc as a function without needing the function keyword.
Type Unsets
To remove a declare type attribute, include the flag with no assignment:
declare -i myint # set
declare +i myint # unset
Helpful for testing and debugging variable types.
Scoping Variables
By default Bash uses global variables accessible to entire scripts. Declare can also define variables local only to functions, similar to other languages:
myfunc(){
declare local myvar="local var"
}
myfunc
echo $myvar # error, $myvar only exists in myfunc
The local flag prevents changes inside a function affecting the outer script.
Core Benefits for Development
Why use typed variable declarations in Bash? Key advantages are:
- Input Validation – Enforcing types like integers assists with sanitizing and checking user supplied input
- Prevent Bugs – Type mismatches can lead to subtle and hard to trace bugs
- Self Documenting Code – Type declarations serve as code documentation
- Portability – Well typed code is more reusable across projects
- Performance – Underlying Bash internals can better optimize based on type knowledge
Making variables as strict as needed improves script quality.
Exporting to Environment
The -x flag exports a declared variable as an environment variable, making it available to child processes:
declare -x MYVAR="foo"
echo $MYVAR # "foo"
Then in subshells and external commands launched from script, MYVAR will be accessible. This is extremely useful in build pipelines/automation workflows where you need to pass values between steps.
Read-Only Constants
Read-only values enforce constants, preventing accidental reassignment:
declare -r API_KEY="123abc"
API_KEY="456" # bash: API_KEY: readonly variable
Using constants improves security for sensitive credentials while documenting intent – this variable should NOT change.
The scoping rules apply here too, so we can make read-only values limited to functions.
Variable Name Case Control
By default Bash treats upper and lowercase letters in variable names as distinct – myvar and myVar are different variables. But declare lets us change this behavior.
Lowercase Name Enforcement
The -l flag converts variable assignments to lowercase automatically:
declare -l mixedCase="Value"
echo $mixedcase # value
So the value gets stored in a lower-cased name, useful for standardization.
Uppercase Name Enforcement
Similarly, -u converts names to uppercase:
declare -u lower VAR="val"
echo $LOWER # val
This technique prevents subtle bugs from typos when accessing variables.
Viewing All Declarations
See all declared variables and their options using declare -p:
declare -i myint
declare -r MAX=100
declare -p
Returns output like:
declare -ir myint="5"
declare -r MAX="100"
Summarizing variable types, readonly status, scoping and more.
Declare in Other Languages
For perspective, let‘s compare declare functionality to other languages.
In C and C++, all variables have strict static types like int, float, char[] explicitly set during declaration. Strings must have a max length set. And const defines constants.
Golang uses var to type variables like var myInt int = 5. And const sets read-only values. Values can‘t be re-assigned unlike let in JavaScript.
Rust has explicit types set on variables that are immutable by default. mut allows mutability while const enables constants.
TypeScript adds types to JavaScript with :TypeName syntax and as const marks readonly variables.
The declare command brings this level of strict typing to Bash allowing fine-grained control over script variables.
Use Cases and Examples
With an understanding of declare‘s capabilities, what are some practical examples of putting this to work?
Configuration Constants
Say we have a script that requires API credentials. We should define these securely in code as constants:
#!/bin/bash
declare -r API_TOKEN="123abc456"
# Pass creds to curl command
curl -H "Authorization: Bearer $API_TOKEN" example.com/api
The readonly attribute prevents accidental misuse or overwriting of the token value later in code.
For even better security, restrict declare scope too:
config(){
declare -r local API_TOKEN="123abc456"
}
config
Now the confidential value is only visible to the config function.
Input Validation
Declare assists with checking and sanitizing user supplied input. For example, prompting for age:
read -p "Enter age: " age
declare -i age
if (( age >= 0 )); then
echo "$age years old"
else
echo "Invalid entry" >&2
exit 1
fi
Converting age to an integer upfront either parses the numeric value successfully, or gets set to 0 on failed input, allowing for robust validation.
We can make this into a reusable validate_input function:
validate_int(){
declare -i value="$1"
if (( value > 0 )); then
echo "$value"
else
echo "Invalid" >&2
exit 1
fi
}
read -p "Enter value: " value
validate_int "$value" # tests input
Strict types enhance validation capabilities.
Lookup Tables
Associative declare arrays empower lookup tables for key-value searches:
#!/bin/bash
declare -A users
users[john]="John"
users[jane]="Jane"
users[bob]="Bob"
read -p "Enter username: " user
name=${users[$user]}
if [[ -z $name ]]; then
echo "Unknown user"
exit 1
fi
echo "Name found: $name"
This allows scripts to handle robust name lookups from input, with arrays initialized upfront for easy maintenance.
Conclusion
While Bash provides wide environment access and portable cross-platform automation, some more advanced features found in lower level languages can facilitate writing safer, more foolproof scripts. This is where declare delivers, offering fine-grained control over variable typing, constants, scoping and exporting right within native Bash.
So if you thought Bash lacked capabilities for enterprise-grade coding, think again – the declare command brings enhanced development power. Unlocking declare will level up your Bash scripting skills to support robust automation for system administration, cloud infrastructure, CI/CD, and virtually any Linux environment.


