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.
evaling the output ofdeclare -p IFS. – Charles Duffy Mar 19 '21 at 19:13bashlike in all shells with scoping, you'd rather uselocal(though it works best with shells with static scoping or withzsh'sprivateinstead (not that you'd use$IFSinzsh)) . The output of bash'sdeclare -pis not always safe forevaling. – Stéphane Chazelas Mar 19 '21 at 19:20printf %q'd or equivalent. Have a reference? – Charles Duffy Mar 19 '21 at 19:23evalon 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 -pwithin 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 IFSin itself doesn't work ifIFSis unset. Then,declare -pjust errors out with "-bash: declare: IFS: not found". Instead of e.g. printingunset IFS. – ilkkachu Mar 20 '21 at 09:57unset IFSbefore theevaland you're fine. – Charles Duffy Mar 20 '21 at 13:38declaretoo. 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 -pis 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$IFSin older versions of bash in some locales. Also note that beside theunsetissue, it can't be used in functions asdeclarewould makeIFSlocal upon restore. It also won't restore the type to scalar ifIFSbeen set to array or hash in between. IOW, it has no advantage over safer approaches. – Stéphane Chazelas Mar 21 '21 at 06:42