조건부 파이프라인

조건부 파이프라인

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

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

어떤 경우에는 과 사이에 을 추가하고 싶습니다 cmd3. 결과를 임시 파일에 저장하지 않고 일종의 조건부 파이프라인을 생성하는 방법이 있습니까? 나는 다음과 같은 것을 생각할 것입니다 :cmd2cmd4cmd2

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

답변1

일반적인 &&AND ||연산자:

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

비록 명시된 대로이 답변if ... else, if-else 구문을 사용하는 경우 일반적으로 선호합니다.

  ...
  cmd2 |
  if [ -n "$DEFINED" ]; then cmd3; else cat; fi |
  cmd4 |
  ...

(줄이 파이프로 끝나면 후행 백슬래시가 필요하지 않습니다.)

고쳐 쓰다~에 따르면요나스의 관찰. cmd3이 0이 아닌 종료 코드로 종료될 수 있고 나머지 입력을 처리
하지 않으려면 논리를 반대로 바꾸세요.cat

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

답변2

if// else효율적인 fi. Bourne과 유사한 쉘을 가정하면 다음과 같습니다.

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

답변3

지금까지 제공된 모든 답변은 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/bash -shopt -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에서는 (적어도) + 대신 which를 cat사용하여 두 파이프 간에 데이터를 전달할 수 있으므로 데이터가 커널과 사용자 공간 간에 두 번 이동하는 것을 방지할 수 있습니다.pv -qsplice()read()write()

cmd3또 다른 옵션은 주어진 명령을 파이프로 연결하거나 파이프로 실행 하거나 이에 의존하지 않는 함수를 정의하는 것입니다 $DEFINE.

if [ -n "$DEFINE" ]; then
  maybe_preprocess_with_cmd3() { cmd3 | "$@"; }
  maybe_postprocess_with_cmd3() { "$@" | cmd3; }
else
  maybe_preprocess_with_cmd3() { "$@"; }
  maybe_postprocess_with_cmd3() { "$@"; }
fi

그런 다음:

cmd1 |
cmd2 |
maybe_preprocess_with_cmd3 cmd4 |
... |
cmdN > result.txt

또는:

cmd1 |
maybe_postprocess_with_cmd3 cmd2 |
cmd4 |
... |
cmdN > result.txt

답변4

비슷한 상황이 발생하여 bash를 사용하여 해결했습니다.기능:

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

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

관련 정보