파이프의 한 부분이 완전히 "통과"되도록 지정하는 방법이 있습니까?

파이프의 한 부분이 완전히 "통과"되도록 지정하는 방법이 있습니까?

상당히 큰 파이프를 통해 데이터를 스트리밍하여 처리하는 스크립트가 있습니다. 파이프라인의 여러 부분은 실제로 일부 외부 매개변수를 기반으로 다양한 작업을 수행하는 "스위치보드" 기능입니다. 아래에 인위적인 예가 나와 있습니다.

#! /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아무 것도 하지 않는 프로세스 무리를 만드는 것을 피하고 싶습니다 .

하위 프로세스를 사용하지 않고 파이프의 특정 부분이 STDOUT을 STDIN에 직접 연결하도록 지정하는 데 사용할 수 있는 bash 내장(또는 대안)이 있습니까? (해봤는데 :데이터만 잡아먹네요.) 아니면 cat리소스를 너무 적게 써서 문제가 안되는건가요?

답변1

우선, cat다른 것을 사용해도 큰 차이가 없으므로 신경쓰지 않아도 됩니다.

둘째, 파이프라인을 구성하는 명령은 외부 명령이든 내장 명령이든 별도의 프로세스에서 실행됩니다.

$ a=0
$ a=1 | a=2 | a=3
$ echo $a
0

nop정확한 질문에 관해서는 단순히 "stdin"을 "stdout"에 연결하는 것은 불가능합니다. 쉘 에 파이프에서 사용될 때 충돌이 발생하는 내장 함수가 있더라도 (예: | nop |-> |) 쉘에는 방법이 없습니다. 파이프를 설정할 때 "스위치보드 " nop가 .awksort

파이프라인을 직접 구축한 다음 eval을 호출하여 실행함으로써 "스위치보드"와 동일한 효과를 얻을 수도 있습니다. 예:

$ 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)사용자 영역 안팎으로 데이터를 이동하는 것과 관련되지 않는 시스템 호출입니다.

$ cat splice_cat.c
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdlib.h>
#include <err.h>

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

그러나 (내가 아는 한) shell이나 cat, dd등에서는 그것을 사용하지 않습니다.

관련 정보