파이프를 사용하여 bash 함수를 작성하는 방법은 무엇입니까?


18

이 방식으로 정의 된 함수는 거의 없습니다.

function f {
  read and process $1
  ...
  echo $result
}

호출이 다음과 같이되도록 구성하고 싶습니다 f | g | h.

인수에서 작동하는 함수를 stdin에서 하나의 읽기 인수로 변환하는 데 사용하는 관용구는 무엇입니까? 스트림에서 이스케이프 처리하지 않고 인수, 쌍의 튜플을 읽을 수 있습니까 (예 : 널 종료)?


h(g(f(...)))표준 입력 ( read x; ...) 에서 읽거나 표준 출력 ( echo ...)에 쓰거나 유사한 기능 을 원 하거나 각 기능 을 원합니다 .
vonbrand

답변:


21

잠재적 인 접근 방법 중 하나 while...read는 STDIN을 통해 함수에 들어온 데이터를 처리하고 조작 한 다음 STDOUT을 통해 결과 데이터를 다시 내보내는 구문을 함수 내에 구성하는 것입니다.

function X {
  while read data; do
    ...process...
  done
}

구성 while ..read..요소를 안정적으로 사용할 수있는 데이터 유형에 크게 의존하기 때문에 구성 요소 를 구성하는 방법에주의를 기울여야 합니다. 최적의 구성이있을 수 있습니다.

$ logF() { while read data; do echo "[F:$(date +"%D %T")] $data"; done; }
$ logG() { while read data; do echo "G:$data";                    done; }
$ logH() { while read data; do echo "H:$data";                    done; }

각 기능 자체는 다음과 같습니다.

$ echo "hi" | logF
[F:02/07/14 20:01:11] hi

$ echo "hi" | logG
G:hi

$ echo "hi" | logH
H:hi

우리가 함께 사용할 때입니다.

$ echo "hi" | logF | logG | logH
H:G:[F:02/07/14 19:58:18] hi

$ echo -e "hi\nbye" | logF | logG | logH
H:G:[F:02/07/14 19:58:22] hi
H:G:[F:02/07/14 19:58:22] bye

그들은 다양한 스타일의 입력을 취할 수 있습니다.

#-- ex. #1
$ cat <<<"some string of nonsense" | logF | logG | logH
H:G:[F:02/07/14 20:03:47] some string of nonsense

#-- ex. #2    
$ (logF | logG | logH) <<<"Here comes another string."
H:G:[F:02/07/14 20:04:46] Here comes another string.

#-- ex. #3
$ (logF | logG | logH)
Look I can even
H:G:[F:02/07/14 20:05:19] Look I can even
type to it
H:G:[F:02/07/14 20:05:23] type to it
live
H:G:[F:02/07/14 20:05:25] live
via STDIN
H:G:[F:02/07/14 20:05:29] via STDIN
..type Ctrl + D to stop..

#-- ex. #4
$ seq 5 | logF | logG | logH
H:G:[F:02/07/14 20:07:40] 1
H:G:[F:02/07/14 20:07:40] 2
H:G:[F:02/07/14 20:07:40] 3
H:G:[F:02/07/14 20:07:40] 4
H:G:[F:02/07/14 20:07:40] 5

#-- ex. #5
$ (logF | logG | logH) < <(seq 2)
H:G:[F:02/07/14 20:15:17] 1
H:G:[F:02/07/14 20:15:17] 2

4

slm의 답변에 대한 부록으로 , null로 구분 된 튜플을 함수 인수로 실험했습니다.

$ sayTuple() { 
    IFS= read -r -d $'\0' d1
    IFS= read -r -d $'\0' d2
    echo "sayTuple: -$d1- -$d2-"
}

참고 : input 주변의 모든 공간을 처리 sayTuple하는 null로 끝나는 레코드를 두 번 읽습니다 . 에 의해 뒤 레코드-d $'\0'IFS=echo-

올바르게 함유 널 종료 입력 처리 프로그램 결과 \n\t:

$ printf "%s\0%s\0" "Hello " $' Brave\n\tWorld' | sayTuple 
sayTuple: -Hello - - Brave
        World-

의견 개선을위한 제안을 추가하십시오. 흥미로운 주제입니다.


아이디어가 +1됩니다. 대신 내부에 임의의 # 인수를 취할 수 있도록 루프를 넣을 수 있습니다. sayTuple() { arr=() ; while IFS= read -r -d $'\0' arg; do arr+="$arg"; done; echo "sayTuple: ${arr[@]}"; }.
slm

당신이 할 수 있어야하는 IFS= read -r -d $'\0' -a arg것처럼 보이지만 나는 이것을 작동시킬 수 없었습니다. 이렇게하면을 제거 할 수 있습니다. while불필요 해 보이지만 작동 할 수있는 유일한 패턴이었습니다.
slm
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.