2

I have a function that needs to change IFS for its logic:

my_func() {
  oldIFS=$IFS; IFS=.; var="$1"; arr=($var); IFS=$oldIFS
  # more logic here
}

Can I declare IFS as local IFS inside the function so that I don't need to worry about backing its current value and restore later?

codeforester
  • 39,467
  • 16
  • 112
  • 140

4 Answers4

10

It appears to work as you desire.

#!/bin/bash
changeIFSlocal() {
    local IFS=.
    echo "During local: |$IFS|"
}
changeIFSglobal() {
    IFS=.
    echo "During global: |$IFS|"
}
echo "Before: |$IFS|"
changeIFSlocal
echo "After local: |$IFS|"
changeIFSglobal
echo "After global: |$IFS|"

This prints:

Before: |
|
During local: |.|
After local: |
|
During global: |.|
After global: |.|
JM0
  • 340
  • 1
  • 13
Barmar
  • 741,623
  • 53
  • 500
  • 612
5

Yes it can be defined!

As long as you define it local, setting of the value in the function does not affect the global IFS value. See the difference between the snippets below

addNumbers () {
    local IFS='+'
    printf "%s\n" "$(( $* ))"
}

when called in command-line as,

addNumbers 1 2 3 4 5 100
115

and doing

nos=(1 2 3 4 5 100)
echo "${nos[*]}"

from the command line. The hexdump on the above echo output wouldn't show the IFS value defined in the function

echo "${nos[*]}" | hexdump -c
0000000   1       2       3       4       5       1   0   0  \n
000000e

See in one of my answers, how I've used the localized IFS to do arithmetic - How can I add numbers in a bash script

Inian
  • 80,270
  • 14
  • 142
  • 161
3

I got confused because I changed the value of IFS to : inside the function (without using local) and then tried to display the value of IFS with this command, after calling the function:

echo $IFS

which displayed an empty line that made me feel the function wasn't changing IFS. After posting the question, I realized that word splitting was at play and I should have used

echo "$IFS"

or

printf '%s\n' "$IFS"

or, even better

set | grep -w IFS=

to accurately display the IFS value.

Coming back to the main topic of local variables, yes, any variable can be declared as local inside a function to limit the scope, except for variables that have been declared readonly (with readonly or declare -r builtin commands). This includes Bash internal variables like BASH_VERSINFO etc.

From 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, a variable
assignment error occurs, or the shell is not executing a function.
codeforester
  • 39,467
  • 16
  • 112
  • 140
2

You can designate IFS as a local variable; the local version is still used as the field separator string.

Sometimes it is useful to run a function in a completely isolated environment, where no changes are permanent. (For example, if the function needs to change shell options.) This can be achieved by making the function run in a subshell; just change the {} in the function definition to ():

f() ( 
  shopt -s nullglob
  IFS=.
  # Commands to run in local environment
)
rici
  • 234,347
  • 28
  • 237
  • 341