I know that a custom IFS value can be set for the scope of a single command/built-in. Is there a way to set a custom IFS value for a single statement?? Apparently not, since based on the below the global IFS value is affected when this is attempted
#check environment IFS value, it is space-tab-newline
printf "%s" "$IFS" | od -bc
0000000 040 011 012
\t \n
0000003
#invoke built-in with custom IFS
IFS=$'\n' read -r -d '' -a arr <<< "$str"
#environment IFS value remains unchanged as seen below
printf "%s" "$IFS" | od -bc
0000000 040 011 012
\t \n
0000003
#now attempt to set IFS for a single statement
IFS=$'\n' a=($str)
#BUT environment IFS value is overwritten as seen below
printf "%s" "$IFS" | od -bc
0000000 012
\n
0000001
Best Answer
In some shells (including
bash
):(with
bash
, you can omit thecommand
if not in sh/POSIX emulation). But beware that when using unquoted variables, you also generally need toset -f
, and there's no local scope for that in most shells.With zsh, you can do:
$=PATH
is to force word splitting which is not done by default inzsh
(globbing upon variable expansion is not done either so you don't needset -f
unless in sh emulation).However, in
zsh
, you'd rather use$path
which is an array tied to$PATH
, or to split with arbitrary delimiters:p=(${(s[:])PATH})
orp=("${(s[:]@)PATH}")
to preserve empty elements.(){...}
(orfunction {...}
) are called anonymous functions and are typically used to set a local scope. with other shells that support local scope in functions, you could do something similar with:To implement a local scope for variables and options in POSIX shells, you can also use the functions provided at https://github.com/stephane-chazelas/misc-scripts/blob/master/locvar.sh. Then you can use it as:
(by the way, it's invalid to split
$PATH
that way above except inzsh
as in other shells, IFS is field delimiter, not field separator).Is just two assignments, one after the other just like
a=1 b=2
.A note of explanation on
var=value cmd
:In:
The shell executes
/path/to/cmd
in a new process and passescmd
andarg
inargv[]
andvar=value
inenvp[]
. That's not really a variable assignment, but more passing environment variables to the executed command. In the Bourne or Korn shell, withset -k
, you can even write itcmd var=value arg
.Now, that doesn't apply to builtins or functions which are not executed. In the Bourne shell, in
var=value some-builtin
,var
ends up being set afterwards, just like withvar=value
alone. That means for instance that the behaviour ofvar=value echo foo
(which is not useful) varies depending on whetherecho
is builtin or not.POSIX and/or
ksh
changed that in that that Bourne behaviour only happens for a category of builtins called special builtins.eval
is a special builtin,read
is not. For non special builtin,var=value builtin
setsvar
only for the execution of the builtin which makes it behave similarly to when an external command is being run.The
command
command can be used to remove the special attribute of those special builtins. What POSIX overlooked though is that for theeval
and.
builtins, that would mean that shells would have to implement a variable stack (even though it doesn't specify thelocal
ortypeset
scope limiting commands), because you could do:Or even:
with
myfunction
being a function using or setting$a
and potentially callingcommand eval
.That was really an overlook because
ksh
(which the spec is mostly based on) didn't implement it (and AT&Tksh
andzsh
still don't), but nowadays, except those two, most shells implement it. Behaviour varies among shells though in things like:though. Using
local
on shells that support it is a more reliable way to implement local scope.