Why is there a /bin/echo and why would I want to use it?

18,527

Solution 1

If you open up a bash prompt and type in an echo command, that uses a shell builtin rather than running /bin/echo. The reasons it is still important for /bin/echo to exist are:

  1. You're not always using a shell. Under a variety of circumstances, you run an executable directly and not through a shell.
  2. At least in theory, some shells don't have an echo builtin. This is not actually required.

To expand on #1, suppose you wanted to move all the regular files whose names started with abc anywhere in src to dest. There are several ways to do that but one of them is:

find src -name 'abc*' -type f -exec mv -nv {} dest/ \;

But suppose, rather than just running that, you want to see every command that will be run first. Well, then you can prepend echo to the command, just as you might in other contexts:

find src -name 'abc*' -type f -exec echo mv -nv {} dest/ \;

But find doesn't use a shell. That runs /bin/echo.

Besides find with -exec or -execdir, the /bin/echo executable will be called by other programs that themselves run programs but not through a shell. This happens with the xargs command (which is related to find), as well as in a number of other contexts, such as the Exec= line of a .desktop file. Another example is when you run sudo echo, which can be handy for testing if sudo is working.

Similarly, some shells have a printf builtin but /usr/bin/printf also exists.

A less common possible reason you might deliberately use /bin/echo is if you were relying on the differences between it and the echo command provided by your shell. man echo documents /bin/echo; help echo in bash documents the bash builtin. echo is not very portable, because different implementations--both across operating systems and across shells on the same operating system--support different options (e.g., -e) and differ in their treatment of backslashes. Of course, it's better to avoid relying on such details, and use printf instead, which is far more portable.

In bash, you can make the type builtin show /bin/echo as well--assuming /bin is in your $PATH as it always should be--by passing it the -a flag:

$ type -a echo
echo is a shell builtin
echo is /bin/echo

Solution 2

Eliah's done a great job of answering this, but I want to comment about the "why is there another version of echo separate from the Bash program" part. That's the wrong question.

The right question is: why is this a builtin in the first place, when it could have been (and is) a perfectly fine external command?

For simplicity, take a look at the builtins in dash, a measly 38 (bash has 61, for comparison, going by the output of compgen -b):

.               continue        getopts         readonly        type
:               echo            hash            return          ulimit
[               eval            jobs            set             umask
alias           exec            kill            shift           unalias
bg              exit            local           test            unset
break           export          printf          times           wait
cd              false           pwd             trap
command         fg              read            true

How many of these need to be builtins? [, echo, false, printf, pwd, test, and true don't need to be builtins: They don't do anything that only a builtin can do (affect or obtain shell state that's not available to external commands). Bash's printf at least takes advantage of being a builtin: printf -v var saves the output to the variable var. time in bash is also special: by being a keyword, you can time arbitrary command lists in bash (dash doesn't have a time equivalent). pwd doesn't need to be a builtin either - any external command is going to inherit the current working directory (and it's an external command too). : is an exception - you need a NOP, and : is it. The rest do actions that an external command can easily do.

So, a fifth of these builtins don't need to be builtins. Why, then? The dash manpage* actually explains in passing why these are builtins (emphasis mine):

Builtins
 This section lists the builtin commands which are builtin because they
 need to perform some operation that can't be performed by a separate
 process.  In addition to these, there are several other commands that may
 be builtin for efficiency (e.g.  printf(1), echo(1), test(1), etc).

That's pretty much it: these builtins are there because they're used so often, interactively and in scripts, and their functionality is simple enough, that the shell can do the job. And so it happens: some (most?) shells took on the job.** Go back to the sh from 2.9 BSD, and you won't find an echo builtin.

So, it's entirely possible a minimal shell can skip implementing such commands as builtins (I don't think any current shell does, though). The GNU coreutils project doesn't assume that you're going to run them in a particular shell, and POSIX requires these commands. So, coreutils provides these anyway, and skips those which don't have any meaning outside of the shell.


* This is almost identical to the corresponding manpage text for the Almquist shell, which is what dash, the Debian Almquist shell, is based on.

** zsh takes this idea to the extreme: the commands you get by loading various modules, like zmv, are things you wouldn't think a shell need even get into. At that point, the real question is: why would you use bash instead of zsh, which has all these builtins?

Share:
18,527

Related videos on Youtube

Zanna
Author by

Zanna

Updated on September 18, 2022

Comments

  • Zanna
    Zanna over 1 year

    I noticed that there is a binary executable /bin/echo on my Ubuntu MATE 17.04 system.

    I thought, that's odd, because

    $ type echo
    echo is a shell builtin

    Cursory testing suggests that /bin/echo does the same sort of thing as the Bash builtin echo:

    $ /bin/echo foo
    foo
    $ /bin/echo $USER
    zanna
    

    So, why is there another version of echo separate from the Bash program, and why or when would I want to use it?

    • Panther
      Panther over 6 years
    • Eliah Kagan
      Eliah Kagan over 6 years
      @bodhi.zazen That's quite useful even though it's not the same, because it addresses the converse of this question. That question asks why echo is provided as a shell builtin, while this one asks why it is provided as an external command.
    • jamesqf
      jamesqf over 6 years
      One reason is that not everyone uses bash. I would guess that /bin/echo predates bash, and the developers found it useful/efficient to include it as a built-in instead of using the executable.
  • fiatux
    fiatux over 6 years
    And also because the POSIX specification says there has to be one.
  • Eliah Kagan
    Eliah Kagan over 6 years
    @glennjackman I was hoping someone would post an answer about that, actually, and I hope you decide to do so! There's some subtlety involved, though, as neither Debian, Ubuntu, nor GNU Coreutils (nor the GNU Project overall) try to comply with POSIX in everything. For example, POSIX insists a cd executable exist (which, when run, changes directory and quits, leaving the caller where they were before) and some OSes have one. It may be helpful to cite 4.1 in the GNU standards.
  • Joshua
    Joshua over 6 years
    @EliahKagan: Incidentaly /usr/bin/cd has a use: /usr/bin/cd directory command runs that command in that directory. If the directory change fails the command doesn't start.
  • Joshua
    Joshua over 6 years
    It turns out that : doesn't need to be a builtin either. It's just silly for it to not be a builtin. Unless you're dealing with early init rescue-floppy-disk level problems (in which case I discovered the hard way pwd doesn't work reliably either) the only penalty for not having this as a builtin is terrible performance.
  • muru
    muru over 6 years
    @Joshua no, : as an external wouldn't really be a NOP, you'd still have PATH lookup, an attempt to execute the command, etc., when all you really want is to expressly do nothing. : as a builtin does that.
  • Eliah Kagan
    Eliah Kagan over 6 years
    @Joshua But POSIX doesn't call for that behavior, does it? Regular builtins are to be implemented exec()ably too, which includes cd, requiring a cd executable, but it need only do what the builtin does, so it needn't accept a command operand. I'm not sure what systems support /usr/bin/cd dir cmd, but it's unportable even across fully POSIX OSes. (And IMHO a command to simulate (cd dir && cmd) would be better off not named cd.)
  • Peter Cordes
    Peter Cordes over 6 years
    Bash actually does need pwd to be built-in for it to work the way it does, with the default behaviour of showing the "logical" path (pwd -L). /bin/pwd could only implement the pwd -P behaviour of showing you the actual parent directories, not the symlink you cded through.
  • muru
    muru over 6 years
    @PeterCordes pwd's status is a bit compromised by the presence of PWD, but yes, that's also an instance of bash using the builtin status to improve functionality
  • muru
    muru over 6 years
    @Joshua a better use of cd is simply as a test of ability to access a given directory: if /usr/bin/cd some/dir succeeds, in one shot you have tested: a) that some/dir exists, b) that it's a directory or a link to one, and c) the required permissions for you to access that directory exist; all without changing your own state.
  • anna328p
    anna328p over 6 years
    /bin isn't in my $PATH, because I use a different Linux distro (Arch) that symlinks /bin to /usr/bin.
  • Eliah Kagan
    Eliah Kagan over 6 years
    @Ferrybig No, POSIX demands the opposite: an argument to echo that starts with - is still a string operand, except the first argument--and then only if it's -n (though, in practice, implementations often support other options). mv doesn't start with -. 1003.1-2008 demands this, as did 1003.1 and SUSv2; none says anything like what you've stated or even contains the word "undefined."
  • Eliah Kagan
    Eliah Kagan over 6 years
    @Ferrybig That's not to say the commands I've shown are portable, only that - isn't why they aren't. The one without echo is unportable as mv need only support -i and -f. The one with echo is unportable as the path find passes it may contain \, giving implementation-defined behavior. Conforming echos are permitted to translate backlash escapes, which is undesired here. Ubuntu's /bin/echo is GNU Coreutils echo, which doesn't.
  • Carl Witthoft
    Carl Witthoft over 6 years
    FWIW, echo and \bin\echo have slightly different capabilities. Back in my crazy shell-scripting days, I occasionally had one of them call the other to get exactly the information I wanted printed in exactly the format I wanted.
  • Wildcard
    Wildcard over 6 years
    @CarlWitthoft, see Why is printf better than echo? Also it's /bin/echo, not \bin\echo, unless you're using Windows. ;)