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