When I wrote my last two tools multicode and epoch, I wanted them to work with input arguments, as well as used in a chain of a pipeline (a Unix pipe). Here are examples of the two input methods.
Let’s assume we have the input
Njg2NTZjNmM2ZjIwNzQ2ODY1NzI2NTBhCg== for the command
Using the argument, the input data is just added after the command name:
Using the Unix pipe
|, the input data is the result of the previous command. Here, the example is very synthetic, as the first command (
echo), is just returning the given input unmodified. The result of
echo, will be the input of the next command (
Here is a second example using the pipe command. This time with four commands.
And another representation of the above line with the intermediate results for a better understanding:
echo hello there->
» Analysing gofmt
How can we make our program use both, input from arguments and the pipe? After I’ve searched for it and did not find any results, I thought that I already know at least one Go tool which works like this:
gofmt (which formats go code to a specific style).
You can use it and give a file name as an argument, or input the code directly, using the pipe. So the functionality is a bit different between the two options. Reading a file and processing the content, or processing the content without the step of reading a file first.
gofmt will read the given file(s):
gofmt uses the source code directly as printed by
So, I’ve just checked the source of
gofmt and found the right place in the code:
Basically, all of the magic is checking the number of input arguments (
flag.NArg()). When there are no arguments, use the values from
stdin (the data from the pipe or directly input. If directly input, use
CTRL-D to signal the end of the input).
If the number of arguments is not zero, check if the input is a file (or directory) and process with the data from the given path instead of using
You can see, how the
processFile function allows handling both inputs. Here is the signature of the function:
So, it contains the logic of first reading a file, or skipping this step and using the input directly.
» Minimal Example
Here is how I adopted the code for my tools. I have an even simpler use case, as I don’t have to read the data from a file, just using the plain input in both cases:
After processing the
input will contain the same data, regardless which input method was used.
You can find the minimal example program in my playground repo.