비어 있지 않은 리턴에 조건부로 파이프 만들기


16

한 함수의 출력을 다른 함수로 파이프하는 방법이 있습니까? 하지만 출력 있는 경우에만 가능 합니까?


답변:


9

다음 ifnotempty함수는 입력이 비어 있으면 아무것도하지 않는 것을 제외하고 인수로 전달 된 명령에 입력을 파이프합니다. 을 써서 파이프에 source --foo연결 하십시오 .sink --barsource --foo | pipe_if_not_empty sink --bar

pipe_if_not_empty () {
  head=$(dd bs=1 count=1 2>/dev/null; echo a)
  head=${head%a}
  if [ "x$head" != x"" ]; then
    { printf %s "$head"; cat; } | "$@"
  fi
}

디자인 노트 :

  • 이 구현은 모든 POSIX / Unix 플랫폼에서 작동 할 것으로 기대하지만 엄격하게 말하면 표준을 준수 dd하지는 않습니다. 표준 입력에서 읽도록 지시 된 1 바이트 이상을 읽지 않아야합니다.
  • 나는 리눅스 head -c 1에서 적합한 대안 이라고 생각 dd bs=1 count=1 2>/dev/null합니다.
  • 반면에 일반적으로 입력을 버퍼링하고 출력하는 한 줄 이상을 읽을 수 head -n 1있기 때문에 적합하지 않으며 head파이프에서 읽으므로 여분의 바이트가 손실됩니다.
  • read -r head심지어 read -r -n 1 head첫 번째 문자가 개행 인 경우, 때문에 여기에 적합하지 않은 head빈 문자열로 설정됩니다 빈 라인으로 시작하는 빈 입력과 입력을 구별 할 수 없도록.
  • head=$(head -c 1)첫 번째 문자가 줄 바꿈이면 명령 대체가 마지막 줄 바꿈을 제거하여 빈 줄과 빈 줄로 시작하는 입력을 구분할 수 없으므로 쓸 수 없습니다 .
  • bash, ksh 또는 zsh에서는 미세한 성능 향상 cat</dev/stdin위해 대체 할 수 있습니다 .

전체 중간 데이터를 메모리에 저장하는 것이 마음에 들지 않으면 여기에 매우 간단한 구현이 pipe_if_not_empty있습니다.

pipe_if_not_empty () {
  input=$(cat; echo a);
  if [ "x$input" != x"a" ]; then
    { printf %s "${input%a}"; } | "$@"
  fi
}

다음과 같은 경고를 사용하여 약간 더 간단한 구현이 있습니다.

  • 소스에서 생성 된 데이터는 개행 문자로만 구성된 경우에만 비어있는 것으로 간주됩니다. (이것은 실제로 바람직 할 수 있습니다.)
  • 소스에 의해 생성 된 데이터가 끝나는 개행 수에 관계없이 싱크에 공급 된 데이터는 정확히 하나의 개행 문자로 끝납니다. (문제 일 수 있습니다.)

다시, 전체 데이터는 메모리에 저장됩니다.

pipe_if_not_empty () {
  input=$(cat);
  if [ "x$input" != x"" ]; then
    { printf '%s\n' "${input}"; } | "$@"
  fi
}

17

이것은 당신을 위해 작동합니다

$ --a function-- | [ xargs -r ] --another function--

$ echo -e "\n\n" | xargs -r ls
$ # No output. ls did not run.
$ echo -e "\n\n1" | xargs -r ls
ls: cannot access 1: No such file or directory

간단하지만 그것은 당신을 위해 작동합니다. "함수"가 빈 문자열을 보내거나 파이프 라인 아래로 줄 바꿈을 보내면 xargs -r은 "다른 기능"으로 전달되지 않습니다.

xargs에 대한 참조 : http://www.oreillynet.com/linux/cmd/cmd.csp?path=x/xargs

-r, --no-run-if-empty
Do not run command if standard input contains only blanks.


4

아래 함수는 첫 번째 바이트를 읽으려고 시도하고 성공하면 해당 바이트를 에코하고 나머지는 고양이로 만듭니다. 효율적이고 100 % 휴대 가능해야합니다.

if_read() {
    IFS="" read -rN 1 BYTE && { echo -nE "$BYTE"; cat; } | "$@";
}

테스트 사례 :

$ echo -n | if_read wc -c
$ echo | if_read wc -c
1
$ echo -en "\nX" | if_read wc -c
2
$

이 함수는 내가 실행할 때 실패합니다 echo -en "\nX" | pipe_if_not_empty mail -s "Subject line here" foo@bar.com. 그것은 생각 line하고 here있지 주제에 토큰, 전자 메일의 모두받는 사람입니다. 나는 "그 주제를 둘러보기 위해 피해야한다 . 그러나 pipe_if_not_empty수락 된 답변 의 기능은 아무것도 탈출하지 않아도 나에게 효과적입니다.
kuzzooroo

2

적어도 이런 식으로 작동합니다 :

yourcommand | if [ $(wc -c) -gt "0" ]; then yourothercommand; fi

위의 내용은 줄 바꿈 및 기타 특수 문자를 출력으로 간주하므로 if 문에 빈 줄이 전달되면 출력으로 간주됩니다. 출력이 보통 1 바이트보다 높아야하는 경우 -gt 제한을 늘리십시오. :)


yourothercommand의 출력을 보지 못합니다 yourcommand.
추후 공지가있을 때까지 일시 중지되었습니다.

2

대신 sender | receiver:

tester () { local a=$(</dev/stdin); if [[ $a ]]; then printf '%s\n' "$a" | receiver; fi; }
sender | tester

또는 Gilles의 답변에서와 같이 수신 프로그램을 인수로 수락하도록 변경하여보다 일반적인 목적으로 만들 수 있습니다.

tester () { local a=$(</dev/stdin); if [[ $a ]]; then printf '%s\n' "$a" | "$@"; fi; }
sender | tester receiver
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.