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; :'