조건부 파이프 라인


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(또는 ||) 변경 입력 유지 널 조작으로서 작용한다. 그래서 교체 catecho변화의 모든 코드는 무관하게. “거짓 또는 잘못”에 관해서는 파이프 라인과의 간섭이 없습니다 : pastebin.com/u6Jq0bZe
manatwork

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