I am looking for a program or (probably C)-code which I will refer to as route which takes a bytestring/stream on stdin and routes it to one of n programs, based on the intial few bytes (the prefix). The prefix will not be forwarded/piped to the destination program. I would imagine it would have a commandline interface like:
echo -n 'for-p1.perform-operation-A' | route 'for-p1.' >(program1) 'for-p2.' >(program2) echo -n 'for-p2.perform-operation-B' | route 'for-p1.' >(program1) 'for-p2.' >(program2) in the example given above, program1 would receive 'perform-operation-A' (as if I had executed `echo 'perform-operation-A' | program1), program2 would receive 'perform-operation-B'. The prefix always precedes the (virtual) filename of the destination.
Is there any existing solution for doing this or do I have to roll my own?
EDIT: By popular request, here is my 30min attempt at a solution, but I would vastly prefer existing solutions, or at least recommendations for libraries for the steps:
/* build: sudo apt install -y build-essential && g++ main.cpp usage example: ( rm output* || true echo -n "foo-hello" | ./a.out 2>/dev/null 'foo-' >(cat | tee -a output-foo) 'bar-' >(cat | tee -a output-bar) 1>/dev/null echo -n "bar-world" | ./a.out 2>/dev/null 'foo-' >(cat | tee -a output-foo) 'bar-' >(cat | tee -a output-bar) 1>/dev/null echo echo -n "output-foo: " ; cat output-foo ; echo echo -n "output-bar: " ; cat output-bar ; echo ) */ #include <fcntl.h> #include <stdio.h> #include <map> #include <string> using namespace std; typedef FILE* File; #define hasKey(map, key) (map.find((key)) != map.end()) // I assume this is pretty inefficient, looking for a good solution void pipeRest(File fromFile, File toFile) { size_t bytesRead = 0; do { char data; bytesRead = fread(&data, 1, 1, fromFile); if (bytesRead) fwrite(&data, 1, 1, toFile); } while (bytesRead > 0); } int main( int const argc, char const * const * const argv ) { if (argc <= 1) { fprintf(stderr, "usage:\n\n\troute prefix1 >(ouput-program-1) prefix2 >(output-program-2) ...\n\nreads from stdin, recognizes any of n prefixes and pipes the rest to the filename following the prefix\n"); exit(1); } // Parse [prefix outputFile] pairs from commandline args map<string, string> prefixesToOutputFileNames; map<string, File> prefixesToOutputFiles; for (int i = 0; i < argc; i++) { fprintf(stderr, "argv[%d] = '%s'\n", i, argv[i]); if (i > 0 && i % 2 == 0) { auto const prefix = argv[i - 1]; fprintf(stderr, "prefix = '%s'\n", prefix); auto const outputFileName = argv[i]; fprintf(stderr, "outputFileName = '%s'\n", outputFileName); prefixesToOutputFileNames[prefix] = outputFileName; auto const outputFile = fopen(outputFileName, "wb"); prefixesToOutputFiles[prefix] = outputFile; } } // Start reading bytes from stdin, collect the prefix freopen(0, "rb", stdin); string prefix = ""; char nextPrefixChar[2] = { 0 }; size_t bytesRead = 0; do { bytesRead = fread(nextPrefixChar, 1, 1, stdin); prefix += nextPrefixChar; fprintf(stderr, "read %zd bytes = '%s', prefix = '%s'\n", bytesRead, bytesRead ? nextPrefixChar : 0, prefix.c_str()); if (hasKey(prefixesToOutputFiles, prefix)) { // Prefix found -> pipe to corresponding output file auto const outputFileName = prefixesToOutputFileNames[prefix]; fprintf(stderr, "prefix '%s' was recognized, will pipe rest to '%s'\n", prefix.c_str(), outputFileName.c_str()); auto const outputFile = prefixesToOutputFiles[prefix]; pipeRest(stdin, outputFile); exit(0); } } while (bytesRead > 0); fprintf(stderr, "input ends and did not recognize any prefix, rest will be piped to stdout\n"); pipeRest(stdin, stdout); return 0; }
routes it to one of n programs-The prefix always precedes the (virtual) filename- so route to filenames or to programs? Routing to files/pipes is simpler. But why not just write it in shell?How do you copy stdin most efficiently to an output file?Please one question per post. Have you started writing such C program? What research did you do? What part of that C program are you having problem with?tee >(sed -n 's/^for.p1.//p' | program1) | sed -n 's/^for.p2.//p' | program2and forget about it?I have written such a programThen please post it.