조건부 파이프 라인


39

다음 파이프 라인이 있다고 가정 해 보겠습니다.

cmd1 < input.txt |\
cmd2 |\
cmd4 |\
cmd5 |\
cmd6 |\
(...) |\
cmdN > result.txt

특정 조건에서 cmd3사이에 cmd2와 를 추가하고 싶습니다 cmd4. cmd2의 결과를 임시 파일로 저장하지 않고 친절한 조건부 파이프 라인을 만드는 방법이 있습니까? 나는 다음과 같은 것을 생각할 것이다.

cmd1 < input.txt |\
cmd2 |\
(${DEFINED}? cmd3 : cat ) |\
cmd4 |\
cmd5 |\
cmd6 |\
(...) |\
cmdN > result.txt

답변:


36

평소 &&와 ||연산자 :

cmd1 < input.txt |
cmd2 |
( [[ "${DEFINED}" ]] && cmd3 || cat ) |
cmd4 |
cmd5 |
cmd6 |
(...) |
cmdN > result.txt

선이 파이프로 끝날 때 후행 백 슬래시는 필요하지 않습니다.

Jonas의 관찰 에 따라 업데이트하십시오 .
cmd3이 0이 아닌 종료 코드로 종료 cat되고 나머지 입력을 처리 하지 않으려면 논리를 반대로하십시오.

cmd1 < input.txt |
cmd2 |
( [[ ! "${DEFINED}" ]] && cat || cmd3 ) |
cmd4 |
cmd5 |
cmd6 |
(...) |
cmdN > result.txt

편리한 팁 주목!
— 반전

6
개는 알고 있어야합니다 : unix.stackexchange.com/a/39043/19055
— 조나스 콜커

2
논리를 바꾸는 것은 도움이되지 않습니다. cat종료 상태가 0이 아닌 상태로 리턴 되면 (SIGPIPE를 가져올 때 일반적) cmd3실행됩니다. Thor의 답변 이나 달리기를 피하는 다른 솔루션 에서와 같이 if / then / else를 사용하는 것이 더 좋습니다 cat.
— Stéphane Chazelas

고양이는 사물을 연결하는 데 사용될 수 있습니다
— 알렉산더 밀스

19

if/ else/ fi작동합니다. Bourne과 같은 쉘을 가정 :

cmd1 < input.txt |
cmd2 |
if [ -n "$DEFINED" ]; then cmd3; else cat; fi |
cmd4 |
cmd5 |
cmd6 |
(...) |
cmdN > result.txt

10

지금까지 제공된 모든 답변은로 대체 cmd3됩니다 cat. 다음을 사용하여 명령을 실행하지 않아도됩니다.

if [ -n "$DEFINE" ]; then
  alias maybe_cmd3='cmd3 |'
else
  alias maybe_cmd3=''
fi
cmd1 |
cmd2 |
maybe_cmd3
cmd4 |
... |
cmdN > result.txt

POSIX이지만 모드 가 아닌 bash스크립트 (예 :로 시작하는 스크립트 )에서는 (또는 ) 를 사용하여 별칭 확장을 활성화해야합니다 .bashsh#! /path/to/bashshopt -s expand_aliasesset -o posix

여전히 불필요한 명령을 실행하지 않는 또 다른 방법은 eval을 사용하는 것입니다.

if [ -n "$DEFINE" ]; then
  maybe_cmd3='cmd3 |'
else
  maybe_cmd3=''
fi
eval "
  cmd1 |
  cmd2 |
  $maybe_cmd3
  cmd4 |
  ... |
  cmdN > result.txt"

또는:

eval "
  cmd1 |
  cmd2 |
  ${DEFINE:+cmd3 |}
  cmd4 |
  ... |
  cmdN > result.txt"

Linux에서 (적어도) 대신에 cat, 당신이 사용할 수있는 pv -q사용하는 splice()대신 read()+ write()데이터가 커널과 사용자 공간 사이에 두 번 이동 가진 피한다 두 파이프 사이에 걸쳐 데이터를 전달 할 수 있습니다.


9

manatwork의 인정 된 답변에 대한 부록으로서 : 거짓과 허위와 스트림과의 상호 작용에주의하십시오. 예를 들어

true && false || echo foo

출력 foo. 당연히

true && (echo foo | grep bar) || echo baz

과

echo foo | (true && grep bar || echo baz)

두 출력 baz. (이는 echo foo | grep bar거짓이며 출력이 없습니다.) 하나,

echo foo | (true && grep bar || sed -e abaz)

아무것도 출력하지 않습니다. 이것은 당신이 원하는 것일 수도 아닐 수도 있습니다.


나는 이것이 어떻게 관련이 있는지 볼 수 없습니다. 는 else(또는 ||) 변경 입력 유지 널 조작으로서 작용한다. 그래서 교체 cat와 echo변화의 모든 코드는 무관하게. “거짓 또는 잘못”에 관해서는 파이프 라인과의 간섭이 없습니다 : pastebin.com/u6Jq0bZe
— manatwork

5
@manatwork : 조나스가 지적되는 것은, 즉이다 [[ "${DEFINED}" ]] && cmd3 || cat, cmd3그리고 cat상호 배타적이지 then와 else같은의 지점을 if하지만, 경우에하는 것이 cmd3실패, 다음 cat도 실행됩니다. (물론, 경우에 cmd3항상 성공, 또는 모든 입력을 소비하는 경우에 남아 아무것도 없다, 그래서 stdin를 위해 cat다음이 문제가되지 않을 수 있습니다, 방법에 관한 것이다.) 당신이 모두 필요한 경우 then와 else가지, 그것은 명시 적으로 사용하는 것이 좋습니다 if명령하지를 &&하고 ||.
— musiphil December

1
설명을 주셔서 감사합니다, @musiphil. 이제 나는 조나스의 주장을 이해합니다.
— manatwork

4

bash 함수로 해결 한 비슷한 상황이있었습니다 .

if ...; then
  my_cmd3() { cmd3; }
else
  my_cmd3() { cat; }
if

cmd1 < input.txt |
cmd2 |
my_cmd3 |
cmd4 |
cmd5 |
cmd6 |
(...) |
cmdN > result.txt

3


의사 파이프 라인을 만들기 위해 명명 된 파이프를 연결 하는 다른 가능한 해결책 이 있습니다.

dir="$(mktemp -d)"
fifo_n='0'
function addfifo {
 stdin="$dir/$fifo_n"
((fifo_n++))
[ "$1" ] || mkfifo "$dir/$fifo_n"
stdout="$dir/$fifo_n"; }

addfifo; echo "The slow pink fox crawl under the brilliant dog" >"$stdout" &

# Restoring the famous line: "The quick brown fox jumps over the lazy dog"
# just replace 'true' with 'false' in any of the 5 following lines and the pseudo-pipeline will still work
true && { addfifo; sed 's/brilliant/lazy/' <"$stdin" >"$stdout" & }
true && { addfifo; sed 's/under/over/'     <"$stdin" >"$stdout" & }
true && { addfifo; sed 's/crawl/jumps/'    <"$stdin" >"$stdout" & }
true && { addfifo; sed 's/pink/brown/'     <"$stdin" >"$stdout" & }
true && { addfifo; sed 's/slow/quick/'     <"$stdin" >"$stdout" & }

addfifo -last; cat <"$stdin"

wait; rm -r "$dir"; exit 0

2

나중에 참조하기 위해 여기에 물고기의 조건부 파이프를 찾으러 오는 경우 다음과 같이하십시오.

set -l flags "yes"
# ... 
echo "conditionalpipeline" | \
  if contains -- "yes" $flags 
    sed "s/lp/l p/"
  else
    cat
  end | tr '[:lower:]' '[:upper:]'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.