You can save and assign to IFS as needed. There is nothing wrong with doing so. It's not uncommon to save its value for restoration subsequent to a temporary, expeditious modification, like your array assignment example.
As @llua mentions in his comment to your question, simply unsetting IFS will restore the default behavior, equivalent to assigning a space-tab-newline.
It's worth considering how it can be more problematic to not explicitly set/unset IFS than it is to do so.
From the POSIX 2013 edition, 2.5.3 Shell Variables:
Implementations may ignore the value of IFS in the environment, or the absence of IFS from the environment, at the time the shell is invoked, in which case the shell shall set IFS to <space> <tab> <newline> when it is invoked.
A POSIX-compliant, invoked shell may or may not inherit IFS from its environment. From this follows:
- A portable script cannot dependably inherit IFS via the environment.
- A script that intends to use only the default splitting behavior (or joining, in the case of
"$*"
), but which may run under a shell which initializes IFS from the environment, must explicitly set/unset IFS to defend itself against environmental intrusion.
N.B. It is important to understand that for this discussion the word "invoked" has a particular meaning. A shell is invoked only when it is explicitly called using its name (including a #!/path/to/shell
shebang). A subshell -- such as might be created by $(...)
or cmd1 || cmd2 &
-- is not an invoked shell, and its IFS (along with most of its execution environment) is identical to its parent's. An invoked shell sets the value of $
to its pid, while subshells inherit it.
This is not merely a pedantic disquisition; there is actual divergence in this area. Here is a brief script which tests the scenario using several different shells. It exports a modified IFS (set to :
) to an invoked shell which then prints its default IFS.
$ cat export-IFS.sh
export IFS=:
for sh in bash ksh93 mksh dash busybox:sh; do
printf '\n%s\n' "$sh"
$sh -c 'printf %s "$IFS"' | hexdump -C
done
IFS is not generally marked for export, but, if it were, note how bash, ksh93, and mksh ignore their environment's IFS=:
, while dash and busybox honor it.
$ sh export-IFS.sh
bash
00000000 20 09 0a | ..|
00000003
ksh93
00000000 20 09 0a | ..|
00000003
mksh
00000000 20 09 0a | ..|
00000003
dash
00000000 3a |:|
00000001
busybox:sh
00000000 3a |:|
00000001
Some version info:
bash: GNU bash, version 4.3.11(1)-release
ksh93: sh (AT&T Research) 93u+ 2012-08-01
mksh: KSH_VERSION='@(#)MIRBSD KSH R46 2013/05/02'
dash: 0.5.7
busybox: BusyBox v1.21.1
Even though bash, ksh93, and mksh do not initialize IFS from the environment, they re-export their modified IFS.
If for whatever reason you need to portably pass IFS via the environment, you cannot do so using IFS itself; you will need to assign the value to a different variable and mark that variable for export. Children will then need to explicitly assign that value to their IFS.
$' \t\n'
if you're using bash.unset $IFS
simply doesn't always restore it to what you'd expect to be the default. – Darrel Holt Jun 28 '19 at 17:57IFS
and "restored" it latter, setting it to an empty string. which is why assumingIFS
is set is not safe. – llua Jan 15 '21 at 22:46IFS
's state. While not in the novel format that this site seems to prefer, the answer by barefoot (or sls) should've been accepted since it also points out the problem with blindly saving the variable. – llua Jan 19 '21 at 20:33