0

I'm not quite versed on the terminal, but the few things I've known and read lead me to believe that printf is much more powerful and confortable than echo but work for similar (if not same) purposes. So I asked myself, is it sensible to alias echo to printf so I can forget about any issues with echo? Or is there something I don't see like portability or else?

If needed, system is Ubuntu 20.04 running on WSL2 on Windows 10.

2 Answers 2

5

No, it is not sensible to do so.

printf works very different to echo, you should rather change your habits and use printf when possible (always, but for easy tasks more complicated and more to think about) and/or beneficial/necessary (when variables involved, repetitions, special chars, formating of numbers, etc.).


Just one simple example:

$ echo "100%"
100%

$ printf "100%"
bash: printf: `%': missing format character

Another example:

$ echo "Hello" "World"
Hello World

$ printf "Hello" "World"
Hello

Note also, for printf, that after Hello there is no newline.

This is, because the first argument to printf is the FORMAT string:

printf FORMAT [ARGUMENT]...

See also man printf.

2
  • Thanks for your answer. I highly appreciate your time and kindness in it. But it prompts a doubt on me, isn't the appropriate response to the first difference changing double quotes for single? And I will check that man, although I'm afraid I might not understand all of it
    – tms8bltrn
    Commented Feb 14, 2022 at 14:20
  • Double or single quotes make no difference in the first example, you could even leave them out and have the same effect (same for the second example btw). % is not special to bash or echo, but to printf
    – pLumo
    Commented Feb 14, 2022 at 14:20
0

If you are okay with arguments being printed on separate lines, you could do this:

alias echo='printf "%s\n"'  # name 'echo' is kind of misleading, though

Then

$ echo "100%"
100%
$ echo hello world  # this line has two arguments, "hello" and "world" 
hello
world
$ echo "hello world"  # this line has a single argument, the argument contains a space
hello world
$ echo -n -e -d -- \n \t '\n' '\t'  # this line has eight arguments
-n
-e
-d
--
n
t
\n
\t
$ echo $'hello\nworld'  # this line has a single argument, the argument contains a newline
hello
world

This is still different from real echo — the latter prints its arguments separated by spaces, not newlines:

$ builtin echo hello world  # `builtin` is used to ignore alias
hello world
$ command echo hello world  # `command` is used to ignore builtins and aliases
hello world

Note: at this point echo is an executable program in $PATH, a bash built-in, and an alias (three different implementations); you can see it using type -a echo. (To learn about bash built-ins, run help <name>, e.g. help command, help builtin, help echo, help type, help help).

Personally, I have a script called print (in my $PATH), that behaves exactly this way.

#!/bin/bash -e
printf -- "%s\n" "$@"

I find this behavior much more useful than real echo, because:

  • It makes debugging of shell scripts much easier when I want to figure out what exact sequence of arguments is passed to a command.
  • Even if you want to print multiple words separated by spaces, in most cases you can achieve it with proper escaping, using a single argument (print "x = $x, y = $y"). Escaping is a good habit anyway. Disadvantage compared to echo: it doesn't allow you to abuse bash word splitting in order to remove "extra" spaces between words:
    $ a='hello   '
    $ b='  world   '
    $ c='    ! '
    $ echo "$a $b $c"  # escaping (double quotes) keeps all spaces
    hello      world        ! 
    $ echo $a $b $c  # bash word splitting removes extra spaces between arguments
    hello world !
    
    but you can achieve it with read and bash array:
    <<<"$a $b $c" read -r -a abc; print "${abc[*]}"
    

Alias

Note, in general, having a script (an executable in $PATH) instead of alias is more flexible, because

  • it's not restricted to a single shell (what if you wanna switch from bash to zsh, fish etc one day)
  • you can easily call it from other scripts (you cannot call .bashrc aliases and functions in other bash scripts)
  • you can pass an executable name as an argument to other programs (see xargs, time, watch, find), use in configuration files, or in-line scripts (bash -c 'cmd1 | cmd2; cmd3')

aliases (and shell functions) are well-suited to save typing in interactive shell. You usually use them to:

  • tweak default behavior of interactive tools (enable colors, add safeguards for dangerous commands)
  • create multiple (shorter? clearer?) names for the same command
  • trigger shell builtins (cannot be done from external script)

E.g. one could define alias mv='mv -i' in Archlinux to prevent mv from destroying their willingness to use Archlinux files by mistake. I use alias locate='locate --basename' because it's a more reasonable default for me. Someone could alias z=cd if they think cd is too long.

Name

Note, I have not aliased echo to my script, instead I use a different name (print). Some people say "if you make breaking changes, change the name" (I cannot find quotes, but it feels like some ancient wisdom).

If you find or implement a "good" echo, it's gonna be incompatible with a true, "evil" echo.

So should you alias echo?

echo is mostly bad for scripting. But in scripts:

  • user-defined aliases are not working anyway;
  • author expected echo to behave exactly the way it currently does. Even if you could — you should not change the behavior of standard tools.

echo itself is a safe operation as long as you type and run it interactively (until you pipe its output to destructive commands without double-checking). If you are really annoyed by its behavior and going to start using another tool, you could define an alias for echo, but it will only affect your interactive shell.

# these are similar to real echo, without -n or -e options
alias echo="python3 -c 'import sys; print(*sys.argv[1:])'"
alias echo='bash -c '\''printf "%s\n" "$*"'\'' echo'

# actually, better use functions. Functions are advanced aliases!
function echo() { printf "%s\n" "$*"; }  # safe echo
function echo_n() { printf "%s" "$*"; }  # safe echo -n

If you decide to use a tool that differs from echo significantly (printf or my suggested script that prints newlines between arguments), using the name echo is rather misleading and may be a bad habit (if you ask). When you start writing scripts, you must remember that echo in scripts is different from your alias.

Bonus: A good (?) echo alias

alias echo='echo echo is EVIL! use printf instead; :'

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .