If you are designing a machine to cut wood, you would think that the input would be wood in quantity and that parameters such as cutting thickness would be set for the duration of the task.
Many tasks on data relate to this analogy. It lends itself to a wide variety of arrangements and architectures: chaining (pipes), parallelization, distribution. The paradigm is very flexible and powerful.
wood > board 15cm | style moulding | transport | varnishing | transport > deposit
So the questions "on what" and "in what way" are answered first. If a task can work on an arbitrarily large volume of something, it is necessarily an input, so the other information are settings or arguments.
Well-designed programs are filters, that is, they simply cooperate through pipes. You will notice that very common programs sed, grep, awk, gzip, cat, md5sum, base64, bash, ssh
etc. are designed to read standard input. Alternatively, they also admit file names as arguments, which are data sources and not the data itself. Filename is metadata whilst content is data.
md5sum < /etc/crontab # don't care metadata
md5sum /etc/crontab # same result with metadata
rm
is equivocal, if it were to accept an entry, it could be the paths to be deleted, but it seemed more convenient to keep them as arguments.
In any case there are many ways to switch from the input stream to the arguments. When transforming input into arguments, one must take into account the limits of the interpreter and other parsing traps (quotes, separators, substitutions)
ls | xargs -d'\n' rm # apply rm according to arg length limits
# NOT broken by spaces in filenames
# broken by newlines in filenames
ls | parallel -m rm # apply rm whith many parallel processes
# NOT broken by spaces in filenames
# broken by newlines in filenames
ls | while read;do rm "$REPLY";done # apply rm one by one
# NOT broken by spaces in filenames
# broken by newlines in filenames
ls | split -l1 --filter='read && rm "$REPLY"'
# why make it simple when you can make it complicated
rm $(ls) # apply rm all at once
# broken by arg length limit
# broken by space in filenames
rm * # apply rm all at once
# broken by arg length limit
# NOT broken by newline in filenames
(Conclusion: if you want problems, put newlines in filenames)
Sometimes, when you process business data, you tend to put in arguments some informations that caracterize the data, for example the type of data to process or other metadata. I think that it is a good idea to make difference between metadata and other arguments. metadata would take place naturally with the data, provided that the machine is able to read it and adapt.
Example:
hard wood > board 15cm | style moulding | transport | varnishing | transport > deposit
In this case, you have gain if the cutting and moulding machines are able to adapt their power and blades, instead of an operator that would check the tunings.
There are many examples of programs that put some metadata and data together to build a single datastream:
tar -cf- /etc | tar -tf-
Finally, in a largely distributed business workflow, you should clearly make difference between informations that only concern a particular tasks, that is local arguments, and informations that follow the input, data and metadata, especially since traceability is desired.
Yet another thing to know: arguments are publicly visible by the command ps
, so it is a very bad idea to design a program with a secret argument. Instead use an indirect input method.
cat
, the phone you use to dial someone isrm
. If I made an appliance, how do I make it read phone numbers (if that is one of the things it needs to do)?cat
transfers data (some may be filenames),rm
removes files. They need to process their input differently.xargs cmd
converts a list of items tocmd args
.echo
orprintf
convert their args to a list. (In either case, quoting and other gloss will require attention.)