How do I correctly run a few commands with an altered value of the IFS
variable (to change the way field splitting works and how "$*"
is handled), and then restore the original value of IFS
?
I know I can do
(
IFS='my value here'
my-commands here
)
to localize the change of IFS
to the sub-shell, but I don't really want to start a sub-shell, especially not if I need to change or set the values of variables that needs to be visible outside of the sub-shell.
I know I can use
saved_IFS=$IFS; IFS='my value here'
my-commands here
IFS=$saved_IFS
but that seems to not restore IFS
correctly in the case that the original IFS
was actually unset.
Looking for answers that are shell agnostic (but POSIX).
Clarification: That last line above means that I'm not interested in a bash
-exclusive solution. In fact, the system I'm using most, OpenBSD, does not even come with bash
installed at all by default, and bash
is not a shell I use for anything much other than to answer questions on this site. It's much more interesting to see solutions that I may use in bash
or other POSIX-like shells without making an effort to write non-portable code.
eval
ing the output ofdeclare -p IFS
. – Charles Duffy Mar 19 '21 at 19:13bash
like in all shells with scoping, you'd rather uselocal
(though it works best with shells with static scoping or withzsh
'sprivate
instead (not that you'd use$IFS
inzsh
)) . The output of bash'sdeclare -p
is not always safe foreval
ing. – Stéphane Chazelas Mar 19 '21 at 19:20printf %q
'd or equivalent. Have a reference? – Charles Duffy Mar 19 '21 at 19:23eval
on anything that has been quoted with anything other than the single-quote based approaches there (and even then, it's best to avoid evaling arbitrary data if that can be avoided) – Stéphane Chazelas Mar 19 '21 at 19:35declare -p
within a single Bash script would be a problem? It seems to focus on differences between shells, and mentions a number of different ways for producing quoted versions of a variable, so it's rather hard to pick up what issue you're referring to. – ilkkachu Mar 20 '21 at 09:53declare -p IFS
in itself doesn't work ifIFS
is unset. Then,declare -p
just errors out with "-bash: declare: IFS: not found". Instead of e.g. printingunset IFS
. – ilkkachu Mar 20 '21 at 09:57unset IFS
before theeval
and you're fine. – Charles Duffy Mar 20 '21 at 13:38declare
too. A bit like with theunset IFS [ -n "${save+set}" ] && IFS=$save;
case below (it's exactly the same workaround of course, since in the other direction you can justdeclare -p IFS 2> /dev/null
) – ilkkachu Mar 20 '21 at 13:47IFS=“Xy“ command
– eckes Mar 20 '21 at 17:13declare -p
is not safe to use in a different locale from that where it was generated, like when the part in between the saving and restoring changes the value ofLC_*
/LANG
... variables. It's also unsafe for some values of$IFS
in older versions of bash in some locales. Also note that beside theunset
issue, it can't be used in functions asdeclare
would makeIFS
local upon restore. It also won't restore the type to scalar ifIFS
been set to array or hash in between. IOW, it has no advantage over safer approaches. – Stéphane Chazelas Mar 21 '21 at 06:42