GNU yes(1) analogue #27

Open
opened 2024-01-01 00:14:27 -07:00 by emma · 8 comments
Owner

How should we implement this style of tool?

Implementation ideas include:

  • simplified version that takes no arguments
  • complete GNU rewrite
  • as part of an echo(1)/printf(1) analogue with a repeat option
How should we implement this style of tool? Implementation ideas include: - simplified version that takes no arguments - complete GNU rewrite - as part of an echo(1)/printf(1) analogue with a repeat option
emma added the
enhancement
question
labels 2024-01-01 00:14:27 -07:00
trinity was assigned by emma 2024-01-01 00:14:27 -07:00
Owner

echo -r, -r being "reverberate", would be delightful, but echo(1p) is implementation dependent enough as-is.

speak has historically been used for text-to-speech, so maybe not the best name under which to put an echo.

Plan 9 from User Space uses an echo (notably, with a -n option) and no yes(1) that I can see. I presume yes(1) would be accomplished easily in rc(1). I don't know it but here it is in sh(1):

while :; do printf '%s\n' y; done

Argument echoing is a tough cookie because so many utilities do it. There are at least four designed for the task; echo(1) (POSIX, but they advise against its use for printf(1p) due to wildly varying implementations), printf(1p), prompt(1) (not POSIX and as far as I know rarely implemented, I'll explain further in the following paragraphs), and yes(1) (not in POSIX). To briefly describe all of them as background:

echo(1p), described in A Research UNIX Reader (pg. 7), prints its arguments to standard output, space-delimited and with a trailing newline.

00000000  68 65 6c 6c 6f 20 77 6f  72 6c 64 0a              |hello world.|
0000000c

prompt(1), described in the same paragraph, was replaced with echo(1)'s -n option, which is the heritage from which Plan 9's echo(1) derives. It prints without the newline:

00000000  68 65 6c 6c 6f 20 77 6f  72 6c 64                 |hello world|
0000000b

I really like prompt(1) and it being a separate utility to do this because echo(1) never reliably has any particular option. I've implemented both in C and Rust already but I had trouble with being able to output non-UTF-8 arguments in Rust so if we were to import one of these into the coreutils tree C would be the way to go for now.

printf(1p) is POSIX's answer to echo(1)'s unreliability in arguments. Standardized and based on a standardized language library feature (printf(3p) from the C standard library, particularly <stdio.h>), printf(1p) rarely differs in implementation, though its syntax isn't the prettiest:

$ printf %s 'hello world'
hello world$ printf '%s\n' 'hello world'
hello world
$

It takes C format strings but with some fiddly bits attached to make it more convenient for shell scripting.

Finally, there's yes(1), which is echo(1) but forever:

$ yes
y
y
y
y
# infinity truncated

The only utility we really need to implement is printf(1p), after which we can write echo(1), prompt(1), and yes(1) in shell. I would prefer echo(1) and prompt(1) to be in C because they're small and easily debugged though any actual benefit from this would be little to none. yes(1) could be easily done in shell as well no matter what's implemented. Its usage in the GNU coreutils seems to be the same as echo(1) (as in, it spits out its arguments space-delimited newline-terminated) but with repetition.

If arguments weren't supported I imagine it would be awkward to bend yes(1) to one's uses:

$ yes hello world
Usage: yes
$ yes
y
y
y
^C
$ yes | sed 's:y:hello world:'
hello world
hello world
hello world
^C

So I would prefer to just support arguments. It wouldn't really take much more effort. It doesn't seem to have any specific options though GNU yes(1)'s man page is quite short and the GNU website documentation for yes(1) is shorter so I'm not sure.

`echo -r`, `-r` being "reverberate", would be delightful, but echo(1p) is implementation dependent enough as-is. `speak` has historically been used for text-to-speech, so maybe not the best name under which to put an `echo`. Plan 9 from User Space uses an [echo](https://github.com/9fans/plan9port/blob/master/src/cmd/echo.c) (notably, with a `-n` option) and no yes(1) that I can see. I presume yes(1) would be accomplished easily in rc(1). I don't know it but here it is in sh(1): ```sh while :; do printf '%s\n' y; done ``` Argument echoing is a tough cookie because so many utilities do it. There are at least four designed for the task; echo(1) (POSIX, but they advise against its use for printf(1p) due to wildly varying implementations), printf(1p), prompt(1) (not POSIX and as far as I know rarely implemented, I'll explain further in the following paragraphs), and yes(1) (not in POSIX). To briefly describe all of them as background: echo(1p), described in [A Research UNIX Reader](https://www.cs.dartmouth.edu/~doug/reader.pdf) (pg. 7), prints its arguments to standard output, space-delimited and with a trailing newline. ```sh 00000000 68 65 6c 6c 6f 20 77 6f 72 6c 64 0a |hello world.| 0000000c ``` prompt(1), described in the same paragraph, was replaced with echo(1)'s `-n` option, which is the heritage from which Plan 9's echo(1) derives. It prints without the newline: ```sh 00000000 68 65 6c 6c 6f 20 77 6f 72 6c 64 |hello world| 0000000b ``` I really like prompt(1) and it being a separate utility to do this because echo(1) never reliably has any particular option. [I've implemented both in C and Rust already](https://git.sr.ht/~trinity/src/tree/main/item/echo) but [I had trouble with being able to output non-UTF-8 arguments in Rust](https://trinity.moe/blah/2023-10-31.html) so if we were to import one of these into the coreutils tree C would be the way to go for now. [printf(1p)](https://www.man7.org/linux/man-pages/man1/printf.1p.html) is POSIX's answer to echo(1)'s unreliability in arguments. Standardized and based on a standardized language library feature (printf(3p) from the C standard library, particularly `<stdio.h>`), printf(1p) rarely differs in implementation, though its syntax isn't the prettiest: ```sh $ printf %s 'hello world' hello world$ printf '%s\n' 'hello world' hello world $ ``` It takes C format strings but with some fiddly bits attached to make it more convenient for shell scripting. Finally, there's yes(1), which is echo(1) but forever: ```sh $ yes y y y y # infinity truncated ``` The only utility we really need to implement is printf(1p), after which we can write echo(1), prompt(1), and yes(1) in shell. I would prefer echo(1) and prompt(1) to be in C because they're small and easily debugged though any actual benefit from this would be little to none. yes(1) could be easily done in shell as well no matter what's implemented. Its usage in the GNU coreutils seems to be the same as echo(1) (as in, it spits out its arguments space-delimited newline-terminated) but with repetition. If arguments weren't supported I imagine it would be awkward to bend yes(1) to one's uses: ```sh $ yes hello world Usage: yes $ yes y y y ^C $ yes | sed 's:y:hello world:' hello world hello world hello world ^C ``` So I would prefer to just support arguments. It wouldn't really take much more effort. It doesn't seem to have any specific options though [GNU yes(1)'s man page](https://www.man7.org/linux/man-pages/man1/yes.1.html) is quite short and [the GNU website documentation for yes(1)](https://www.gnu.org/software/coreutils/manual/html_node/yes-invocation.html#yes-invocation) is shorter so I'm not sure.
Owner

Here's a fully featured yes(1) in C:

#include <stdio.h> /* fprintf(3), stdout, NULL */
#include <sysexits.h> /* EX_OK */

char *fake_argv[] = {
    (char []) NULL,
    (char []) "yes"
};

int main(int argc, char **argv){
    int i;

    if(argc < 1){
        argc = 2;
        argv = fake_argv;
    }

    for(i = argc; ; i = (i == argc - 1) ? 1 : i + 1)
        fprintf(stdout, "%s%c", argv[i], (i == argc - 1) ? '\n' : ' ');

    return EX_OK;
}

Untested.

Here's a fully featured yes(1) in C: ```c #include <stdio.h> /* fprintf(3), stdout, NULL */ #include <sysexits.h> /* EX_OK */ char *fake_argv[] = { (char []) NULL, (char []) "yes" }; int main(int argc, char **argv){ int i; if(argc < 1){ argc = 2; argv = fake_argv; } for(i = argc; ; i = (i == argc - 1) ? 1 : i + 1) fprintf(stdout, "%s%c", argv[i], (i == argc - 1) ? '\n' : ' '); return EX_OK; } ``` Untested.
Owner

printf(1p) will suck to implement so I'll wanna finish what I've already started before that.

printf(1p) will suck to implement so I'll wanna finish what I've already started before that.
Author
Owner

i didn’t think we would be including printf? didn’t we discuss a different formatting tool?

i didn’t think we would be including printf? didn’t we discuss a different formatting tool?
Owner

printf(1p) would be a nice addition.

On second thought I might be able to implement it in shell without terrible hacks. It seems to do the following:

  • Printing verbatim. This can be achieved with echo(1) or prompt(1).
  • Integer validation (printf '%d\n' "$var"). This could be an int(1) or something.
  • String formatting. We discussed a format(1) utility.

Perhaps printf(1) should be a shell script and echo(1), prompt(1), and some others should be binaries?

printf(1p) would be a nice addition. On second thought I might be able to implement it in shell without terrible hacks. It seems to do the following: - Printing verbatim. This can be achieved with echo(1) or prompt(1). - Integer validation (`printf '%d\n' "$var"`). This could be an int(1) or something. - String formatting. We discussed a format(1) utility. Perhaps printf(1) should be a shell script and echo(1), prompt(1), and some others should be binaries?
Author
Owner

i think we discussed an out(1) command in the past that does what echo does but without the uncertainty that comes with how it’s defined in POSIX. we definitely want a format(1) command but i want to veto most explicitly posixy tool names in the bonsai coreutils, we want as little semantic overlap with it as possible because we want to make clear that our shell is not POSIX and not POSIX-compliant.

A printf(1p) implementation as one of the test scripts in tests/posix/ would be ideal.

i think we discussed an out(1) command in the past that does what echo does but without the uncertainty that comes with how it’s defined in POSIX. we definitely want a format(1) command but i want to veto most explicitly posixy tool names in the bonsai coreutils, we want as little semantic overlap with it as possible because we want to make clear that our shell is *not* POSIX and *not* POSIX-compliant. A printf(1p) implementation as one of the test scripts in `tests/posix/` would be ideal.
Owner

Emma and I just discussed this:

format(1) should be a string formatter akin to printf(1p) but without sucking. out(1) should be a wrapper around format(1) to be an echo(1) equivalent without the POSIX-specified -n option. And yes(1) should also be a wrapper around format(1).

Emma and I just discussed this: format(1) should be a string formatter akin to printf(1p) but without sucking. out(1) should be a wrapper around format(1) to be an echo(1) equivalent without the POSIX-specified `-n` option. And yes(1) should also be a wrapper around format(1).
emma changed title from GNU yes(1) analogue to GNU `yes(1)` analogue 2024-01-23 15:08:38 -07:00
Owner

On second thought, I'm fully on board with dropping printf(1p) and using format(1). I wonder if the name could be better though - I still think "format" is vague.

I don't think out(1) is necessary. Even really fresh beginners to C are taught printf(3p) and that requires the newline to be specified.

I still believe yes(1) should be a shell script, wrapping format(1).

On second thought, I'm fully on board with dropping printf(1p) and using format(1). I wonder if the name could be better though - I still think "format" is vague. I don't think out(1) is necessary. Even really fresh beginners to C are taught printf(3p) and that requires the newline to be specified. I still believe yes(1) should be a shell script, wrapping format(1).
emma added the
help wanted
label 2024-02-07 20:25:47 -07:00
Sign in to join this conversation.
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: bonsai/harakit#27
No description provided.