상당히 큰 파이프를 통해 데이터를 스트리밍하여 처리하는 스크립트가 있습니다. 파이프라인의 여러 부분은 실제로 일부 외부 매개변수를 기반으로 다양한 작업을 수행하는 "스위치보드" 기능입니다. 아래에 인위적인 예가 나와 있습니다.
#! /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
가 .awk
sort
파이프라인을 직접 구축한 다음 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
등에서는 그것을 사용하지 않습니다.