Thread overview
Piping from terminal into D program
Sep 04, 2021
eXodiquas
Sep 04, 2021
Brian Tiffin
Sep 04, 2021
WebFreak001
Sep 04, 2021
eXodiquas
September 04, 2021

Hello everyone,

I created a small little D program that reads in a string from the command line and shuffles the letters of the nouns a bit around. This is pretty straight forward, but what I see now happening is a bit strange, at least for me.

I am reading the args out of the main function arguments.

void main(string[] args) {
  args.writeln();
}

this works fine whenever I call the program like ./nounscramble "Hello, my name is Earl!" the string shows up in args[1]. But when I call echo "Hello, my name is Earl!" | ./nounscramble it does not show up in the args array, the only thing showing up is the name of the executable (which is expected).

My question is now, can someone explain what I am doing wrong? Maybe I misunderstood the pipe in Linux systems and it is obvious for someone who knows how this works exactly, or maybe D works differently with pipes and I havn't found the correct documentation.

Thanks in advance. :)

eXodiquas

September 04, 2021

On Saturday, 4 September 2021 at 15:41:51 UTC, eXodiquas wrote:

>

Hello everyone,

I created a small little D program that reads in a string from the command line and shuffles the letters of the nouns a bit around. This is pretty straight forward, but what I see now happening is a bit strange, at least for me.

I am reading the args out of the main function arguments.

void main(string[] args) {
  args.writeln();
}

this works fine whenever I call the program like ./nounscramble "Hello, my name is Earl!" the string shows up in args[1]. But when I call echo "Hello, my name is Earl!" | ./nounscramble it does not show up in the args array, the only thing showing up is the name of the executable (which is expected).

My question is now, can someone explain what I am doing wrong? Maybe I misunderstood the pipe in Linux systems and it is obvious for someone who knows how this works exactly, or maybe D works differently with pipes and I havn't found the correct documentation.

Thanks in advance. :)

eXodiquas

There are two things happening here. Command line arguments and stdin, standard in.

When part of an actual command line, parameters are expanded as command line arguments, passed to the main function. When echoed, the arguments are passed to the echo command, which then displays those arguments on stdout, standard out. A pipe is connecting the stdout of the left hand side, and streaming that data to the stdin of the right hand side, after the pipe symbol. These are not command line arguments, but data on the stdin/stdout channels (file descriptors to be more exact with the jargon).

You could write is as echo thing | ./nounscramble commandarg.

echo will display thing. Your program with get commandarg in the array passed to main, but the stdout data displayed by echo is never read, and just ends up in a pipeline bitbucket at the end of processing.

Most shells, like bash allow a different kind of parameter replacement, command arg expansion. Use like ./nounstatement $(echo this that), and the shell will manipulate things to replace the stdout from the echo into word expanded arguments placed in the atring array used by main.

Cheers

September 04, 2021

On Saturday, 4 September 2021 at 15:41:51 UTC, eXodiquas wrote:

>

Hello everyone,

I created a small little D program that reads in a string from the command line and shuffles the letters of the nouns a bit around. This is pretty straight forward, but what I see now happening is a bit strange, at least for me.

I am reading the args out of the main function arguments.

void main(string[] args) {
  args.writeln();
}

this works fine whenever I call the program like ./nounscramble "Hello, my name is Earl!" the string shows up in args[1]. But when I call echo "Hello, my name is Earl!" | ./nounscramble it does not show up in the args array, the only thing showing up is the name of the executable (which is expected).

My question is now, can someone explain what I am doing wrong? Maybe I misunderstood the pipe in Linux systems and it is obvious for someone who knows how this works exactly, or maybe D works differently with pipes and I havn't found the correct documentation.

Thanks in advance. :)

eXodiquas

to extend on Brian Tiffin's reply, you can read from the standard input stream (the data piped to your program) using std.stdio's stdin

Example:

import std.stdio;
foreach (line; stdin.byLine)
    writeln("got input line: ", line);
// IMPORTANT: the line buffer is reused (it's a char[], not a string), so if you want to store it in a variable outside the foreach, use .idup to make it a string (that is not changed when leaving the loop)

or

import std.stdio;
foreach (chunk; stdin.byChunk(1024))
    writeln("got input chunk: ", cast(char[])chunk);
// same warning as above, don't case to string (that's unsafe and wouldn't be allowed in @safe code, but casting to char[] is safe, as it explicitly says it can be changed)

or

import std.stdio;
ubyte[1024] buffer;
auto part = cast(char[])stdin.rawRead(buffer[]);
writeln("got part: ", part);
// this is the lower level equivalent of the byChunk above, it's just doing a single step instead of multiple chunks, so you control when it is changed.
// a slice of this buffer (which is what the return value is) needs to be .idup'd to be persisted outside the lifetime of the `buffer` variable
September 04, 2021

On Saturday, 4 September 2021 at 18:20:51 UTC, WebFreak001 wrote:

>

On Saturday, 4 September 2021 at 15:41:51 UTC, eXodiquas wrote:

>

[...]

to extend on Brian Tiffin's reply, you can read from the standard input stream (the data piped to your program) using std.stdio's stdin

[...]

Brian Tiffin's and your reply really cleared things up for me. Thank you very much for the detailed answer and your time.

Have a nice day. :)

September 05, 2021

On Saturday, 4 September 2021 at 15:41:51 UTC, eXodiquas wrote:

>

My question is now, can someone explain what I am doing wrong? Maybe I misunderstood the pipe in Linux systems and it is obvious for someone who knows how this works exactly, or maybe D works differently with pipes and I havn't found the correct documentation.

eXodiquas

Of course, pipe ( | ./nounscramble ) is not args ( ./nounscramble arg1 arg2 ).

Pipe
stdin -> ( read buf -> write buf ) -> stdout

Args
main( args ) -> write arg1, arg2 -> stdout

Check the D std.stdio. https://dlang.org/phobos/std_stdio.html
Check the shell tool xargs. https://en.wikipedia.org/wiki/Xargs