微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

基于前缀将标准输入路由到其他文件/程序的程序?

如何解决基于前缀将标准输入路由到其他文件/程序的程序?

我正在寻找一个程序或(可能是 C)代码,我将其称为 route,它在 stdin 上获取字节串/流并将其路由到 n 个程序之一,基于最初的几个字节(前缀)。前缀不会被转发/管道到目标程序。我想它会有一个命令行界面,如:

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)

在上面给出的例子中,program1 会收到'perform-operation-A'(就像我执行了'echo 'perform-operation-A' | program1),program2 会收到'perform-operation-B'。前缀始终位于目标的(虚拟)文件名之前。

是否有任何现有的解决方案可以做到这一点,还是我必须自己推出?

编辑:根据普遍的要求,这是我 30 分钟的解决方案尝试,但我非常喜欢现有的解决方案,或者至少推荐图书馆的步骤:

/*
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,fromFile);
        if (bytesRead) fwrite(&data,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,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;
}

解决方法

在 bash shell 中,您只需编写:

tee >(sed -n 's/^for\.p1\.//p' | program1) | sed -n 's/^for\.p2\.//p' | program2

以下程序:

filter() {
    keyword=$1
    shift
    # https://stackoverflow.com/questions/407523/escape-a-string-for-a-sed-replace-pattern
    keyword=$(printf '%s\n' "$keyword" | sed -e 's/[]\/$*.^[]/\\&/g');
    LC_ALL=C sed -n "s/^$keyword//p" | "$@"
}
hexfilter() {
    keyword=$1
    shift
    keyword=$(printf '%s\n' "$keyword" | sed -e 's/../[\\x&]/g');
    LC_ALL=C sed -n "s/^$keyword//p" | "$@"
}
program1() { :; }
program2() { :; }

echo -e '\x00\xca\xfe\x2a world!' |
{ tee >(filter 'for.p1.' program1 >&3) >(hexfilter '00cafe2a' sed 's/^/Hello/' >&3) | filter 'for.p2.' program2 >&3; } 3>&1 |
cat

过滤前缀 0x00 0xca 0xfe 0x2a 并输出 Hello world!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?