Skip to content

@dchest /0 - UNIX Fifth Edition
Created

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
UNIX V5, OpenBSD, Plan 9, FreeBSD, and GNU coreutils implementations of echo.c
main(argc, argv)
int argc;
char *argv[];
{
int i;
argc--;
for(i=1; i<=argc; i++)
printf("%s%c", argv[i], i==argc? '\n': ' ');
}
/* $OpenBSD: echo.c,v 1.7 2009/10/27 23:59:21 deraadt Exp $ */
/* $NetBSD: echo.c,v 1.6 1995/03/21 09:04:27 cgd Exp $ */
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* ARGSUSED */
int
main(int argc, char *argv[])
{
int nflag;
/* This utility may NOT do getopt(3) option parsing. */
if (*++argv && !strcmp(*argv, "-n")) {
++argv;
nflag = 1;
}
else
nflag = 0;
while (*argv) {
(void)fputs(*argv, stdout);
if (*++argv)
putchar(' ');
}
if (!nflag)
putchar('\n');
return 0;
}
#include <u.h>
#include <libc.h>
void
main(int argc, char *argv[])
{
int nflag;
int i, len;
char *buf, *p;
nflag = 0;
if(argc > 1 && strcmp(argv[1], "-n") == 0)
nflag = 1;
len = 1;
for(i = 1+nflag; i < argc; i++)
len += strlen(argv[i])+1;
buf = malloc(len);
if(buf == 0)
exits("no memory");
p = buf;
for(i = 1+nflag; i < argc; i++){
strcpy(p, argv[i]);
p += strlen(p);
if(i < argc-1)
*p++ = ' ';
}
if(!nflag)
*p++ = '\n';
if(write(1, buf, p-buf) < 0){
fprint(2, "echo: write error: %r\n");
exits("write error");
}
exits((char *)0);
}
/*-
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if 0
#ifndef lint
static char const copyright[] =
"@(#) Copyright (c) 1989, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)echo.c 8.1 (Berkeley) 5/31/93";
#endif /* not lint */
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/uio.h>
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/*
* Report an error and exit.
* Use it instead of err(3) to avoid linking-in stdio.
*/
static __dead2 void
errexit(const char *prog, const char *reason)
{
char *errstr = strerror(errno);
write(STDERR_FILENO, prog, strlen(prog));
write(STDERR_FILENO, ": ", 2);
write(STDERR_FILENO, reason, strlen(reason));
write(STDERR_FILENO, ": ", 2);
write(STDERR_FILENO, errstr, strlen(errstr));
write(STDERR_FILENO, "\n", 1);
exit(1);
}
int
main(int argc, char *argv[])
{
int nflag; /* if not set, output a trailing newline. */
int veclen; /* number of writev arguments. */
struct iovec *iov, *vp; /* Elements to write, current element. */
char space[] = " ";
char newline[] = "\n";
char *progname = argv[0];
/* This utility may NOT do getopt(3) option parsing. */
if (*++argv && !strcmp(*argv, "-n")) {
++argv;
--argc;
nflag = 1;
} else
nflag = 0;
veclen = (argc >= 2) ? (argc - 2) * 2 + 1 : 0;
if ((vp = iov = malloc((veclen + 1) * sizeof(struct iovec))) == NULL)
errexit(progname, "malloc");
while (argv[0] != NULL) {
size_t len;
len = strlen(argv[0]);
/*
* If the next argument is NULL then this is this
* the last argument, therefore we need to check
* for a trailing \c.
*/
if (argv[1] == NULL) {
/* is there room for a '\c' and is there one? */
if (len >= 2 &&
argv[0][len - 2] == '\\' &&
argv[0][len - 1] == 'c') {
/* chop it and set the no-newline flag. */
len -= 2;
nflag = 1;
}
}
vp->iov_base = *argv;
vp++->iov_len = len;
if (*++argv) {
vp->iov_base = space;
vp++->iov_len = 1;
}
}
if (!nflag) {
veclen++;
vp->iov_base = newline;
vp++->iov_len = 1;
}
/* assert(veclen == (vp - iov)); */
while (veclen) {
int nwrite;
nwrite = (veclen > IOV_MAX) ? IOV_MAX : veclen;
if (writev(STDOUT_FILENO, iov, nwrite) == -1)
errexit(progname, "write");
iov += nwrite;
veclen -= nwrite;
}
return 0;
}
/* echo.c, derived from code echo.c in Bash.
Copyright (C) 1987, 1989, 1991-1997, 1999-2005, 2007-2011 Free Software
Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "echo"
#define AUTHORS \
proper_name ("Brian Fox"), \
proper_name ("Chet Ramey")
/* If true, interpret backslash escapes by default. */
#ifndef DEFAULT_ECHO_TO_XPG
enum { DEFAULT_ECHO_TO_XPG = false };
#endif
void
usage (int status)
{
if (status != EXIT_SUCCESS)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [SHORT-OPTION]... [STRING]...\n\
or: %s LONG-OPTION\n\
"), program_name, program_name);
fputs (_("\
Echo the STRING(s) to standard output.\n\
\n\
-n do not output the trailing newline\n\
"), stdout);
fputs (_(DEFAULT_ECHO_TO_XPG
? N_("\
-e enable interpretation of backslash escapes (default)\n\
-E disable interpretation of backslash escapes\n")
: N_("\
-e enable interpretation of backslash escapes\n\
-E disable interpretation of backslash escapes (default)\n")),
stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
If -e is in effect, the following sequences are recognized:\n\
\n\
"), stdout);
fputs (_("\
\\\\ backslash\n\
\\a alert (BEL)\n\
\\b backspace\n\
\\c produce no further output\n\
\\e escape\n\
\\f form feed\n\
\\n new line\n\
\\r carriage return\n\
\\t horizontal tab\n\
\\v vertical tab\n\
"), stdout);
fputs (_("\
\\0NNN byte with octal value NNN (1 to 3 digits)\n\
\\xHH byte with hexadecimal value HH (1 to 2 digits)\n\
"), stdout);
printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
emit_ancillary_info ();
}
exit (status);
}
/* Convert C from hexadecimal character to integer. */
static int
hextobin (unsigned char c)
{
switch (c)
{
default: return c - '0';
case 'a': case 'A': return 10;
case 'b': case 'B': return 11;
case 'c': case 'C': return 12;
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
}
}
/* Print the words in LIST to standard output. If the first word is
`-n', then don't print a trailing newline. We also support the
echo syntax from Version 9 unix systems. */
int
main (int argc, char **argv)
{
bool display_return = true;
bool allow_options =
(! getenv ("POSIXLY_CORRECT")
|| (! DEFAULT_ECHO_TO_XPG && 1 < argc && STREQ (argv[1], "-n")));
/* System V machines already have a /bin/sh with a v9 behavior.
Use the identical behavior for these machines so that the
existing system shell scripts won't barf. */
bool do_v9 = DEFAULT_ECHO_TO_XPG;
initialize_main (&argc, &argv);
set_program_name (argv[0]);
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
/* We directly parse options, rather than use parse_long_options, in
order to avoid accepting abbreviations. */
if (allow_options && argc == 2)
{
if (STREQ (argv[1], "--help"))
usage (EXIT_SUCCESS);
if (STREQ (argv[1], "--version"))
{
version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, Version, AUTHORS,
(char *) NULL);
exit (EXIT_SUCCESS);
}
}
--argc;
++argv;
if (allow_options)
while (argc > 0 && *argv[0] == '-')
{
char const *temp = argv[0] + 1;
size_t i;
/* If it appears that we are handling options, then make sure that
all of the options specified are actually valid. Otherwise, the
string should just be echoed. */
for (i = 0; temp[i]; i++)
switch (temp[i])
{
case 'e': case 'E': case 'n':
break;
default:
goto just_echo;
}
if (i == 0)
goto just_echo;
/* All of the options in TEMP are valid options to ECHO.
Handle them. */
while (*temp)
switch (*temp++)
{
case 'e':
do_v9 = true;
break;
case 'E':
do_v9 = false;
break;
case 'n':
display_return = false;
break;
}
argc--;
argv++;
}
just_echo:
if (do_v9)
{
while (argc > 0)
{
char const *s = argv[0];
unsigned char c;
while ((c = *s++))
{
if (c == '\\' && *s)
{
switch (c = *s++)
{
case 'a': c = '\a'; break;
case 'b': c = '\b'; break;
case 'c': exit (EXIT_SUCCESS);
case 'e': c = '\x1B'; break;
case 'f': c = '\f'; break;
case 'n': c = '\n'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'v': c = '\v'; break;
case 'x':
{
unsigned char ch = *s;
if (! isxdigit (ch))
goto not_an_escape;
s++;
c = hextobin (ch);
ch = *s;
if (isxdigit (ch))
{
s++;
c = c * 16 + hextobin (ch);
}
}
break;
case '0':
c = 0;
if (! ('0' <= *s && *s <= '7'))
break;
c = *s++;
/* Fall through. */
case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
c -= '0';
if ('0' <= *s && *s <= '7')
c = c * 8 + (*s++ - '0');
if ('0' <= *s && *s <= '7')
c = c * 8 + (*s++ - '0');
break;
case '\\': break;
not_an_escape:
default: putchar ('\\'); break;
}
}
putchar (c);
}
argc--;
argv++;
if (argc > 0)
putchar (' ');
}
}
else
{
while (argc > 0)
{
fputs (argv[0], stdout);
argc--;
argv++;
if (argc > 0)
putchar (' ');
}
}
if (display_return)
putchar ('\n');
exit (EXIT_SUCCESS);
}
@kylebgorman

the original UNIX one was best. The FreeBSD and GNU ones are disgusting.

@aechiara

agree with kylebgorman

@rch

@kylebgorman slightly off -- Plan 9 bests UNIX.

@raggi

this gist fucking nails it.

@kylebgorman
@ericnormand

gnu echo is pretty bad. Is that a goto? I can't believe that code is running on my machine.

@studiosi

@ericnormand goto is recommended by some programming gurus to avoid repetitive error-solving code. @Everybody_Else the programs are not the same... some of them have arguments, other don't... also the complexity of the OS can influence the complexity of the code. Shorter sometimes is not better...

@mrgenixus

The GNU version is best. none of the other's implement --help to print the program's usage, including specifics on the (also not implemented) -E and -e options, which are useful depending on how your script uses echo. Also, vs the SYS V and other older versions, this version of echo doesn't require a shell to properly handle escape sequences or quotes. It also properly detects and uses locales and characters sets. The FreeBSD version does almost none of these things. Also, given the source code above, it would be a simple matter to reimplement echo more simply. Be careful. Some of that extra functionality may be neccesary for your system to function.

@kylebgorman

@pyDav the use of goto in the GNU version could be a function call instead.
@mrgernixus --help is trivial and could be grafted onto the Sys V or (Net|Open)BSD one. While -e triggers useful behaviors, I think this kind of behavior that misses the point of echo and should be done in a shell script if you need it for some reason (also having a flag to turn off non-default behavior is stupid, full stop).

@pete

I had done something similar for cat.c: https://gist.github.com/665971

@mrgenixus The man pages implement the same funcionality as '--help' nicely.

@Leonidas-from-XIV

@pete But they can't tell you what your error is in your particular call. Like "argument should be numeric" or "missing argument" or whatnot.

@ssmccoy

How often does one even use echo.c, anyway?

scott@optimusprime:~> which echo
echo: shell built-in command
@pete

@Leonidas-from-XIV There's no way for the user to screw up in the Plan 9 version, so no need to validate arguments. Only malloc() and write() can fail.

Incidentally, as Plan 9 is always UTF-8, there's no need to handle odd locale settings, either. No reason for -e handling, as escapes can be done in the shell, and thus no need to handle errors on -e. The whole approach is nice, clean, DRY: don't handle problems if you can make them impossible, and don't handle use cases that are handled elsewhere.

@Leonidas-from-XIV

@pete So some programs should have manpages, others should react on wrong input when neccessary? Why not have both input validation and documentation like... GNU coreutils?

@dchest
Owner

@raggi: strlen.c thing is kind of misleading: those versions are not really used on most architectures. You'll find different (mostly asm) implementations in respective /arch/ directories. Here's an example for i386:

@mernen

@ericnormand Yay for cargo-cult fear of goto.

Also, this is not running on your machine. The /bin/echo command is practically never used, since all shells have an echo builtin.

@EmilHernvall

There's a lesson here, but it's not what some people seem to think. We all know that the more time we spend on a project, the more annoyed we get with the code. Sooner or later it always ends up feeling bloated and badly designed. I think there's two reasons:

  • The number of use cases increases. The GNU version undeniably does a lot more than the other versions.
  • The principle of least astonishment. Users don't want programs to be consistent, they want them to do what they want them to do. That requires a lot of extra coding handling all the edge cases.

I think that what we should take away from this is that in many cases complexity in inevitable, and that we should learn to plan for it and handle it. Simplicity isn't always an option.

@pete

@Leonidas-from-XIV There's no "wrong" input to the Plan 9 version of echo, so there's no need to handle errors related to bad input. What input validation could the Plan 9 echo do? And everything ought to have documentation, which on Unixes takes the form of man pages, so yes.

@astro

Wait, echo -e is specific to GNU?

@brettalton

@ssmccoy
@mernen

$ lsb_release -d
Description: Ubuntu 11.04

$ which echo
/bin/echo

$ echo $BASH_VERSION
4.2.8(1)-release

@mernen

@brettalton I know the binary is there, I said it's not used. Compare echo --help and /bin/echo --help and you'll see.

I don't know what shell @ssmccoy is using (his which is clearly a builtin), but you can get a similar answer with type echo.

@meyering

Two more reasons to prefer the GNU version:
Unlike the first two, with GNU echo, "env echo .... > /dev/full" detects and reports the write error.
Unlike the Plan9 and FreeBSD versions, GNU echo does not use malloc, so cannot fail with ENOMEM.

@ssmccoy

@brettalton @mernen I'm using zsh.

@shurane

WIndows is missing :(

@Leonidas-from-XIV

@shurane I believe echo in Windows is only a shell builtin.

@evanphx

@meyering GNU echo uses putchar(2) which is likely backed by fwrite(2) and thus will malloc a back buffer. Looping over argv and passing the strings to write(2) would be the only way to not malloc and the previous implementers believed the extra syscalls hurt the performance of echo.

@paul-vg

@Leonidas-from-XIV I believe Windows is closed-source, anyways.

@l1x
l1x commented

Somebody finally made it obvious why was GNU/Linux a terrible idea :)

@darkturo

Great Gists!, I've never stopped before to read the implementation of echo in GNU. I really liked the NetBSD, and the classic old Unix implementation, both for their simplicity. FreeBSD was playing with too many intermediate variables. And GNU, losts its way trying to bring some backward compatibility, it actually should have focus just in the option parsing and then executing:

  while (argc > 0)
    {
      fputs (argv[0], stdout);
      argc--;
      argv++;
      if (argc > 0)
        putchar (' ');
    }
    if (display_return)
      putchar ('\n');

Just as a reflection, have you checked the differences between gist-1 and the following provided in the previous comments: http://cvsweb.netbsd.org/bsdweb.cgi/src/bin/echo/echo.c?rev=HEAD
The second one, has some additions, probably added to give support to something new or due to some bug fixes (just guessing here). It has been some kind of evolution between these two versions of the same implementation, the same type of evolution that GNU echo may have followed (I may be wrong here ... but I don't think gist-4 was ugly from the very beginning)... Perhaps it is time for a cleanup...

Thanks for collecting this code here :-)

@jvz

The System V version is shit for using printf for such a simple program. The OpenBSD version is using strcmp which is notorious for being insecure. All of these implementations could have been done better, but that's why echo is a shell built in function.

@fuzxxl

And none of them implements POSIX.

@fuzxxl

@astro Yes. An XSI compliant echo actually supports no options at all. See here for how echo is supposed to work: POSIX. 2008 §echo

@RenaKunisaki

I don't understand the first three lines of the first file. Is that an archaic syntax for main()?

@pcoutin

I don't see why the Plan 9 one has to allocate extra memory. It could just be like the UNIX 5th edition one... unless they really only want to call write() only once.

@netinlet

It would be interesting to see the commit histories of all of these implementations, especially the complex ones.

@keithgabryelski

the only one that is unreadable is FreeBSD
Plan 9's is a little silly -- all that copying
Gnu seems clean

If you give in to the need for the need for options (which I do), then you're looking at something more complex than the first version (it was a reasonable thing at the time -- but we all strive for betterment)

@gnusosa

Plan 9 all the way.

@mikefaille

@keithgabryelski
I agree. GNU one is simple and complete but not complex.
It depends on what you need. For basic stuff, don't use optional options.

@pcoutin
04:33      pcoutin > why is echo not like this http://hastebin.com/raw/viyagikiku
04:33      pcoutin > but like this? http://hastebin.com/raw/koxohunumi
04:35         aiju > because it's used to talk to synthetic fs
04:36         aiju > which often want stuff in a single write
04:36         aiju > echo nuke moscow > /mnt/nukefs/ctl

This makes a lot of sense because 9P filesystems often do stuff like

static long
audiowrite(Chan *c, void *vp, long n, vlong)
{
/* ... */
    case Qvolume:  /* allows doing things such as echo master 100 > /dev/volume */
        cb = parsecmd(a, n);  /* requires whole "command" to be passed in one write */
@Gonzih

@ericnormand: there is plenty of goto statements in linux kernel code. and it's considered to be good practice for fast setup/teardown mechanism as far as i know.

@xorgy

The OpenBSD one demonstrates interestingly that argc isn't strictly necessary, I think it's better than the SysV UNIX echo.

That said, the GNU echo is really useful. It helps you generate escape codes and other things which are difficult to do in a shell without doing manual character arithmetic. Just because it's a bit bigger than the other ones(only about 20 times larger, which is nothing, really), doesn't mean it's a bad program.

@xorgy

An interesting hybrid of the OpenBSD implementation, and the SysV behaviour might look something like

#include <stdio.h>

int main(int argc, char *argv[]) {
  ++argv;
  while (*argv) {
    (void)fputs(*argv, stdout);
    putchar(*++argv? ' ': '\n');
  }
}
@asbjornenge

:hear_no_evil: :see_no_evil: :speak_no_evil: love this gist :heart_eyes:

@hauleth

@xorgy - this is unsafe as you have no guarantee that *(argv + argc) == 0.

@goffrie

@hauleth that is actually guaranteed, IIRC.

@sharth

@hauleth, @goffrie

C 2011 Section 5.1.2.2.1 Paragraph 2
argv[argc] shall be a null pointer.

And the same requirement was in C 1989 (at the same location even).

@solidsnack

Although we can all criticize the GNU one, it is the one we're all using...and the Plan 9 implementation has likely done more work inside of side-project VMs than anywhere else. I am trying to learn the right thing from this fact.

@mux

@solidsnack no it's not. 99.9999999% of the time, people will end up using the echo built-in from the shell they are using, which is why this whole comparison is a colossal waste of time. I also can't believe people are actually praising the GNU version for supporting --help which is not only arguably useless, but in fact a bug, as the echo(1) command is rather peculiar and a conforming implementation should simply print "--help" when invoked with that option as a parameter...

-10000000

@yegortimoshenko

@mux Yup, it's a waste to create a separate process to echo something, so usually shells have echo built into them.

@solidsnack I hate GNU. I do my best to avoid their software. Typically when I use Linux kernel, it is Busybox for coreutils, musl for libc, and so on. I have to use GCC and GNU binutils, however, but they are soon to be replaced by clang. Rest of the time I use BSDs.

There are many others who use BSDs. And while BSDs are free from GNU coreutils, GNU echo isn't the one we're all using.

@Kagami

This makes a lot of sense because 9P filesystems often do stuff like

It doesn't make sense why echo's implementation should depend on fs implementation. Looks to me like bad design and hidden complexity (like @studiosi said).

@joudinet

@yegortimoschenko: I trust more GNU than Busybox for the coreutils in terms of security. For example, http://llvm.org/pubs/2008-12-OSDI-KLEE.html found much more vulnerabilities in the Busybox's coreutils than the one from GNU.

@kare

There's a collection of cat.c's too! https://github.com/pete/cats

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.