64

I'm learning bash scripting and found this on my /usr/share/bash-completion, line 305:

local cword words=()

What does it do? All tutorials online are just in the format

local var=value
0

5 Answers 5

153

Although I like answer given by jordanm I think it's equally important to show less experienced Linux users how to cope with such questions by themselves.

The suggested way is faster and more versatile than looking for answers at random pages showing up at Google search results page.

First, all commands that can be run in Bash without typing an explicit path to it such as ./command can be divided into two categories: Bash shell builtins and external commands. Bash shell builtins come installed with Bash and are part of it while external commands are not part of Bash. This is important because Bash shell builtins are documented inside man bash and their documentation can be also invoked with help command while external commands are usually documented in their own man pages or take some kind of flag like -h, --help. To check whether a command is a Bash shell builtin or an external command:

$ type local
local is a shell builtin

It will display how command would be interpreted if used as a command name (from help type). Here we can see that local is a shell builtin. Let's see another example:

$ type vim
vim is /usr/bin/vim

Here we can see that vim is not a shell builtin but an external command located in /usr/bin/vim. However, sometimes the same command could be installed both as an external command and be a shell builtin at the same time. Add -a to type to list all possibilities, for example:

$ type -a echo
echo is a shell builtin
echo is /usr/bin/echo
echo is /bin/echo

Here we can see that echo is both a shell builtin and an external command. However, if you just typed echo and pressed Return a shell builtin would be called because it appears first on this list. Note that all these versions of echo do not need to be the same. For example, on my system /usr/bin/echo takes --help flag while the Bash builtin one doesn't.

Ok, now when we know that local is a shell builtin let's find out how it works:

$ help local
local: local [option] name[=value] ...
Define local variables.

Create a local variable called NAME, and give it VALUE.  OPTION can
be any option accepted by `declare'.

Local variables can only be used within a function; they are visible
only to the function where they are defined and its children.

Exit Status:
Returns success unless an invalid option is supplied, an error occurs,
or the shell is not executing a function.

Note the first line: name[=value]. Everything between [ and ] is optional. It's a common convention used in many man pages and form of documentation in *nix world. That being said, command you asked about in your question is perfectly legal. In turn, ... character means that previous argument can be repeated. You can also read about this convention in some versions of man man:

The following conventions apply to the SYNOPSIS section and can be used
as a guide in other sections.

bold text          type exactly as shown.
italic text        replace with appropriate argument.
[-abc]             any or all arguments within [ ] are optional.
-a|-b              options delimited by | cannot be used together.
argument ...       argument is repeatable.
[expression] ...   entire expression within [ ] is repeatable.

So, at the end of the day, I hope that now you'll have an easier time understanding how different commands in Linux work.

11
  • 10
    Very nice answer. I was reading through it hoping you would address how a beginner could discover for themselves what the array assignment was, just from the code var=(), but I suppose that is a bit much to figure out without even knowing the name of what you're looking for. ;)
    – Wildcard
    Jan 6, 2016 at 3:16
  • Do non-bash shells support local as well?
    – palswim
    Oct 13, 2016 at 19:39
  • 4
    I signed in just so that I can upvote your answer :) Mar 15, 2018 at 12:14
  • 1
    This answer is worth its weight in gold. I cannot thank you enough for taking the time to add this. I knew about man but I did not know about type or help or that help worked on bash keywords. May 6, 2019 at 15:09
  • 1
    Give a man a <>< and feed him for a day. Teach a man to <>< and feed him for a lifetime.
    – vhs
    Oct 18, 2019 at 7:07
43

Your example

local cword words=()

defines a scalar variable cword and an empty array words in the scope of the current function.

local simply declares a variable to have scope only in the currently-defined function, so that the main executing environment cannot "see" the value. You can't use local outside a function. Example

func() {
   nonlocal="Non local variable"
   local onlyhere="Local variable"
}
func
echo $nonlocal 
echo $onlyhere

Output: Non local variable

So $onlyhere wasn't visible outside the scope of the function.

5
  • 4
    This answer makes more sense who are in need of a quick understanding. May 2, 2019 at 13:17
  • Yes, nice answer. Exactly answers the question in short, understandable form. Arkadiusz Drabczyk answer is also great in learning to figure it out myself.
    – Rana Ian
    Aug 27, 2021 at 21:18
  • 1
    this doesn't seem to explain the differences between local foo=value and local bar=()
    – ilkkachu
    Aug 4, 2022 at 20:16
  • @ilkkachu there really isn't a difference wrt local. foo is a scalar variable, whereas bar is an array.
    – Otheus
    Jan 18 at 11:32
  • 1
    @Otheus, yes, and that's exactly what the answer here doesn't state, even though the question looks like it's exactly about the difference between those two
    – ilkkachu
    Jan 18 at 13:02
42

The local keyword can take multiple variables. Providing the variable with a value is optional. Your example declares two variables, cword and words. The words variable is assigned an empty array.

6

It should be noted that Bash is dynamically scoped, which means local doesn't behave how you might expect from other languages.

Observe:

#!/usr/bin/env bash

x=15

print1 () {
    echo "I am printing $x"
}

print2 () {
    local x=44
    print1
}

print1 # prints "I am printing 15"
print2 # prints "I am printing 44"
print1 # prints "I am printing 15"

So essentially this means local doesn't mean "local variable" it means "locally redefined global variable"

1
  • 2
    Great example for a terrifying feature May 23 at 17:30
2

Greetings users of Unix & Linux SE / @alex-santos, here is a full answer to the question a single, comprehensive response!

a busy cat


Question 1

local cword words=()

What does it do?

Answer 1

"The local keyword can take multiple variables. Providing the variable with a value is optional. Your example declares two variables, cword and words." (Thanks @jordanm!)

A possible caveat is SC2155 in that you should declare and assign separately.

That being said it will work except for using multiple declare options between the parameters. Also, note that the declare parameters will apply to all variables (in this case -i). See here Can one declare multiple local variables in one line

The words variable is assigned an empty array. Because the variable is set to a local access level, it must be declared within a shell function. A local variable will override a global variable with the same name without throwing an error. The local variable will only replace the global variables' value during the execution of the function. The global variables' value will be the one being managed outside of any overriding function scope.

Furthermore, a variable that has only been declared within function scope and has not been declared globally or imported will see the code from several of the existing answers below which illustrated this case and the code I added to cover the other cases described below.

*Cheers to @electric-coffee, @Otheus for illustrating one of the cases the 1st function/local scope example below and to *

Using shell functions to demonstrate local/global variables given all permutations of access and scopes.

Case 1. Local scope inaccessible to global scope since it does not exist.

exampleFunction() {
   nonlocal="Non local variable"
   local localToExampleFunctionOnly="Local variable"
}

# Prints "Non local variable".
echo $nonLocal

Case 2. Globally scoped variable overwritten within function scope with a local variable value.

# Set the globally accessible variable value.
globalVariable="Globally accessible variable."

# Prints "Globally accessible variable." to the console from within
# the global context.
echo $globalVariable;

exampleFunction() {
   globalVariable="Locally accessible variable."
   # Prints "Locally accessible variable."
   echo $globalVariable;
}

# Call function, printing "Globally accessible variable." to the console from within
# the global context.
exampleFunction

# Prints "Globally accessible variable." to the console 
# from within the global runtime environment (the original value set to globally accessible scope).
echo $globalVariable 

Case 3. The globally scoped variable referenced within function scope changed at the global scope, and then output from within a second function scope.

# Set the globally accessible variable value.
globalVariable="Globally accessible variable."

# Prints "Globally accessible variable." to the console from within
# the global context.
echo $globalVariable

exampleFunction() {
    # Prints "Globally accessible variable." to the console 
    # from within the function scope context.
   echo $globalVariable;
}

# Call function the first time
exampleFunction

# Prints "Globally accessible variable." to the console 
# from within the global runtime environment.
echo $globalVariable

# Update the globally accessible variable to a new value.
globalVariable="That's all the cases for scoping I can think of..."

# Prints "That's all the cases for scoping I can think of..." to the 
# console from within the global context.
echo $globalVariable; 

# Call function the last time, now that the value has been updated
# from global and local scope.
# Prints "That's all the cases for scoping I can think of..." 
# from the `exampleFunction`.

# Prints "That's all the cases for scoping I can think of..." to the 
# console from within the function scoped context, re-referencing 
# the updated global value and printing it to the terminal's output.
echo $globalVariable

Try to think of function scope as code-space where your local variables can be modified or referenced when executed, without any side effects from the "outer" environment.

To summarize, the words=() is the second local variable being set in this shell script and is of type Array due to the words=() syntax. The () portion initializes to an empty array accessible after its declaration via $words. Access and element via $words[$elementNumericIndex] and set during initialization like words=("bob" "john" "steve")orwords[0]="bob"`.

*Here is the full documentation for using in bash, nix shell variables (setting, accessing, and more).

https://tldp.org/LDP/Bash-Beginners-Guide/html/sect_10_02.html


Question 2

All tutorials online are just in the format

local var=value

Answer 2

As you may already know, this is the more commonly used single value->variable assignment, which is used for maintaining key-to-value variable relationships which encourage code readability, reduces redundancy, and improves performance when re-using the referenced value instead of redeclaring (hard coding the value repeatedly), promotes best practice, and reduces errors due to "fat fingering" a key while reading/setting/declaring the value from the repeated hard-coded version vs the friendly-named variable (also most modern IDE's and even editors support plugins or natively the ability to autocomplete your variables once declared and if in scope and dependant on the position of the cursor while the application is being composed).


Abstract

I combined some of the great answers provided on this thread in order to answer the OP's question fully and concisely.

I stumbled on this and realized that IMO the most correct and succinct way to fully answer our OP's answer is scattered amongst @jordanm, @electric-coffee, @arkadiusz-drabczyk (directs us to a good response output directly from your local terminal's manual in order to address OP's question about declaring a function scoped variable using local.

local cword words=()


local var=value

Some helpful links:

3
  • This post seems to at least answer the question, but the useless chatter makes it hard to find the point. Parts of the ending should probably be comments on other answers.
    – ilkkachu
    Aug 4, 2022 at 20:20
  • @ilkkachu I totally agree. I don't remember writing this, but I must have been going something at the time... I removed some of the non-sense from it, but I still need to make anything relevant more succinct and remove the rest.
    – AlphaG33k
    Jun 7 at 23:06
  • Upvote for the cat
    – maysara
    Sep 4 at 14:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .