首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否有一种方法可以指定一段管道完全“通过”?

问是否有一种方法可以指定一段管道完全“通过”?
EN

Unix & Linux用户
提问于 2018-09-18 03:55:49
回答 1查看 214关注 0票数 4

我有一个脚本,通过一个相当大的管道对数据进行处理。管道的几个部分实际上是“交换机”函数,根据某些外部参数执行不同的操作。下面给出了一个人为的例子。

代码语言:javascript
复制
#! /bin/bash

switchboard() {
    # Select the appropriate command depending on input.
    case "$1" in
        1)
            sort
            ;;
        2)
            awk '{ print $5 }' | sort
            ;;
        *)
            cat  # <= Is there something more optimal here?
            ;;
    esac
}

# The data processing pipeline.
<"$1" tr '[:upper:]' '[:lower:]' | switchboard "$2" | head -n 10

在“交换机”函数中,回退只是使用cat将输入直接发送到输出。这很好,但在我的管道中,我可能会有许多“交换机”,如果可能的话,我想避免创建一堆无所事事的cat进程。

是否有某种bash内置(或替代)可以用来指定管道的给定部分应该直接连接STDOUT和STDIN,而不必使用子进程?(我尝试了:,但这只占用了数据)或者,cat是否使用了如此少量的资源,这不是一个问题吗?

EN

回答 1

Unix & Linux用户

发布于 2018-09-18 11:19:43

首先,使用另一个cat并没有多大的区别,您不应该为此烦恼。

其次,构成管道的命令无论如何都是在单独的进程中执行的,不管它们是外部命令还是内置命令:

代码语言:javascript
复制
$ a=0
$ a=1 | a=2 | a=3
$ echo $a
0

至于您的确切问题,不可能简单地将'stdin‘连接到'stdout';即使一个shell有一些在管道中使用时会崩溃的nop内建物(如| nop | -> |),在它设置管道时,外壳也无法事先知道您的“交换机”将切换到nop而不是awk或sort。

您还可以通过自己构建管道来实现与“交换机”相同的效果,然后调用eval来运行它。示例:

代码语言:javascript
复制
$ cat test.sh
type=`file -zi "$1"`
case $type in
*application/gzip*)     mycat='zcat "$1"';;
*)                      mycat='cat "$1"';;
esac
case $type in
*charset=utf-16le*)     mycat="$mycat | iconv -f utf16le";;
esac
# highlight comments in blue
esc=`printf '\033'`;
mycat="$mycat | sed 's/^#.*/$esc[34m&$esc[m/'"
echo >&2 "$mycat"    # show the built pipeline
eval "$mycat"   # ... and run it
$ iconv -t utf16 test.sh > test16.sh; gzip test16.sh
$ sh test.sh test16.sh.gz

这有点离题,但在linux上有一种更快的方法将stdin复制到stdout (如果其中任何一个是管道的话) -- splice(2) syscall,它不需要将数据来回移动到用户:

代码语言:javascript
复制
$ cat splice_cat.c
#define _GNU_SOURCE
#include 
#include 
#include 

int main(int ac, char **av){
    ssize_t r;
    size_t block = ac > 1 ? strtoul(av[1], 0, 0) : 0x20000;
    for(;;)
            if((r = splice(0, NULL, 1, NULL, block, 0)) < 1){
                    if(r < 0) err(1, "splice");
                    return 0;
            }
}
$ cc -Wall splice_cat.c -o splice_cat
$ dd if=/dev/zero bs=1M count=100 status=none | (time cat >/dev/null)
real    0m0.153s
user    0m0.012s
sys     0m0.056s
$ dd if=/dev/zero bs=1M count=100 status=none | (time ./splice_cat >/dev/null)
real    0m0.100s
user    0m0.004s
sys     0m0.020s

但是(afaik),无论是shell还是cat、dd等等都不使用它。

票数 1
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/469713

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档