IFS - how much do I hate this?


This gets me nearly EVERY TIME!

I’m trying to parse a string that has spaces (mostly for an inline for loop), and the PIECE DE MERDE insists that every space in the input is a CARRIAGE RETURN! WTF?

Yeah - I could set this in my .profile or my .bashrc or my .zshrc - but - I have to admin some 1000+ Linux and Solaris UNIX servers… And I forget about IFS (irritable F–K syndrome? [sic : yeah I know it’s “Internal Field Separator”]) and get unexpected results…

When I remember - I put this at the start of my for loop :

export IFS=$'\n'

What I don’t get is WHY the F that isn’t the default? And sometimes even that doesn’t work and I have to shotgun spray :
export IFS=$(echo -en "\n\b")

e.g. :

export IFS=$'\n' ;for SHIT in $(grep -v \# ADDRESSEE.txt) ; do echo --- $SHIT --- ; IP=$(echo $SHIT|awk '{print $5}') ; HO=$(echo $SHIT|awk '{print $6}') ; echo $HO : $IP ; done

While I’m there - I might have another rant about using awk…

I use awk all the time - but I wish there was a shortcut way of doing echo $VAR |awk '{print $1}' or 2 or 3 or whatever - it just seems overly cumbersome…

I wish there was a way of directly using awk on the string in the $VAR, something like awk '{print $1} $VAR (where $VAR is a string)…

I guess I could make an alias to echo e.g. alias e=“echo” maybe? And hope “e” isn’t used somewhere else? But then I’d have to go and do that on EVERY environment I use regularly :

One customer has SEVEN different “airgapped” (they’re not actually “airgapped” just firewalled) environments, in all of those I keep MobaXterm in the Windows server I access via RDP… But there are also a bunch of admin Linux servers I often use too - I vastly prefer to use an actual Linux shell, to MobaXterm, for a start - MobaXterm uses busybox for most of the GNU toolset, e.g. “cat”, and the cat command in busybox can’t do “cat -n”…

Let me see how many shells I would need to deploy my alias to :

MobaXterm in a Corporate environment
Red Hat Linux 8 in that same Corp env
6x MobaXterm in firewalled environments
1 x Solaris in Corp env
1 x CentOS at another customer
1 x MobaXterm at above customer
1 x MobaXterm at another customer
2 x Linux desktops at home (Ubuntu and/or Pop!)
5 x Raspberry Pi (or other ARM) computers running Debian or Ubuntu
1 x Red Hat 8 headless server
2 x MacOS instances
2 x MobaXterm at yet another customer

and there’s probably more… Hmmm - I might do this… But then I also need to keep in mind, some / many of those are just “bash”, others are ZSH… So I need to bear in mind, whether to use :

  • .bashrc
  • .bash_profile
  • .profile
  • .zshrc

Most times where I’m confronted with .bashrc and .bash_profile, I do both, anyway - 'cause I’m never sure which one to modify… MobaXterm only seems to have .profile - and just tested this echo “alias e=\"echo\"" >> .profile” and it works… should probably do the same with IFS…

I used to keep a “skeleton” version of .zshrc that I’d deploy on a new install (after installing zsh if it isn’t already installed, and then oh-my-zsh [which needs git] and customising my .zshrc with an edited oh-my-zsh profile)…

So I could probably deploy it something like this

for DOT in ".profile .zshrc .bashrc .bash_profile" ; do if [[ -f $DOT ]] && echo "alias e=\"echo\"" >> $DOT ; if [[ -f $DOT ]] && echo "IFS=$'\n" >> $DOT ; done

But that looks cumbersome too! And it doesn’t work… Oh well - back to the drawing board :smiley:

And the drawing board came up with this (i.e. don’t put quotes around the loop elements) :

export IFS=$'\n' ; for DOT in .profile .zshrc .bashrc .bash_profile ; do echo --- $DOT --- ; if [[ -f $DOT ]] && echo "alias e=\"echo\"" >> $DOT ; if [[ -f $DOT ]] && echo "IFS=$'\n" >> $DOT ; done

DANG : above doesn’t / won’t work - 'cause if I’m using inline logic i.e. [[ -f $DOT ]] I don’t need the “if” in front! And putting the “if” in front of it breaks it…
and double DANG!
Different behaviour in different shells :
Bash in MobaXterm :

 21/09/2023   08:55.53   /home/mobaxterm  echo "IFS=$'\n'"

zsh in Debian Bookworm (on a Pi Zero 2W):

 x@albiorix  ~  echo "IFS=$'\n'"   

This thread is now my journal for how to solve these things as simply as possible… For now - I can just do the alias for echo… IFS=$'\n' causes unexpected output… in different shells… Somehow I need to double escape that ‘\n’ or something because ZSH is treating it as an actual carriage return!

Confirmed, works everywhere with bash, treats that \n as an actual carriage return in zsh…

Maybe in zsh, I need to tell it to run bash instead :
maybe exec bash "for loop" or something? Getting a shell script (e.g. via scp) is an option for Linux systems I can directly SSH into - but will be extremely cumbersome for MobaXterm running on a nested layers of Windows RDP (e.g. right now, I’m citrix’ing into the customer, then from Citrix RDP to an “admin” Windows server, and then from there I RDP through an RDGateway into 6 other environments).

Cumbersome - but this is my workaround.
exec /bin/bash
then :
for DOT in .profile .zshrc .bashrc .bash_profile ; do echo --- $DOT --- ; [[ -f $DOT ]] && echo "alias e=\"echo\"" >> $DOT ; [[ -f $DOT ]] && echo "IFS=$'\n'" >> $DOT ; done

I know there’s probably a way to not have that second inline “[[ -f $DOT]] &&” logic but I’m too lazy and can’t be arsed figuring that out…
– update –
I’ve deployed this to maybe a dozen machines and it works…

1 Like