[Tip] A better echo

Often it has been said that echo is neither portable nor correct.
Here is an input.txt:

line1
line2
-n
line4
-en
line6
-x
line8

Then the following fails with BSD/Linux/bash:

while IFS= read line
do
  echo "$line"
done < input.txt

It is elegantly improved by means of an echo function:

echo_(){
  ( IFS=" "; printf "%s\n" "$*" )
}

while IFS= read line
do
  echo_ "$line"
done < input.txt

(Of course you can directly use the printf instead of the echo function.)
Further it provides compatibility with ksh/sh/psh/ash/dash, and even an old Bourne shell might work.

The following is a suite of echo functions that lets you easily go into a script and replace

  • echo with echo_
  • echo -n with echo_n
  • echo -e with echo_e
  • echo -ne or echo -n -e with echo_ne
  • echo -en or echo -e -n with echo_ne (or echo_en )
# Simple echo
echo_(){
  ( IFS=" "; printf "%s\n" "$*" )
}

# Portable echo -n
echo_n() {
  ( IFS=" "; printf "%s" "$*" )
}

# Portable echo -e
echo_e() {
  ( IFS=" "; printf "%b\n" "$*" )
}

# Portable echo -ne
echo_ne() {
  ( IFS=" "; printf "%b" "$*" )
}

alias echo_en=echo_ne
4 Likes

Hi MadeInGermany,

Can't you use:

echo_e() {
  printf "%b\n" "$*" 
}

Instead?

The use of "$*" means that this only works as long as IFS is at the default:

$ IFS=,
$ echo -e "a\nb" c d
a
b c d
$echo_e "a\nb" c d
a
b,c,d
2 Likes

:b:Two times thank you, Scrutinizer!:b:
I didn't yet discover the %b or thought it's a GNUism. But seems to be standard.
Now I set IFS=" " in a sub shell.
I have implemented the fixes in my original post.

1 Like