이름 변수를 기반으로 파이프/리디렉션을 연결하는 Bash 스크립트 루프

이름 변수를 기반으로 파이프/리디렉션을 연결하는 Bash 스크립트 루프

나중에 grep할 여러 출력 라인을 생성하는 명령이 있습니다.

과거 답변을 바탕으로 하나의 긴 명령을 사용하고 모든 필터를 동시에 실행할 수 있다는 것을 알고 있습니다.

https://superuser.com/questions/7448/can-the-output-of-one-command-be-piped-to-two-other-commands

command | tee >(grep filter1 >./filter1) >(grep filter2 >./filter2)

이제 필터 매개변수를 기반으로 구조를 생성한 다음 이를 긴 명령으로 분리할 수 있다면 다음 셸 의사코드와 같이 무거운 작업을 수행하는 스크립트를 작성할 수 있습니다.

filters='filter1 filter2 filter3'
for filter in $filters; do
  SOMEHOW_STORE_REDIRECTIONS+=>(grep $filter > ./${filter})
command | tee >{SOMEHOW_DECOUPLE_STORE_REDIRECTIONS_VAR_INTO_LONG_COMMAND} | cat > /dev/null

답변1

가장 간단한 방법은 한 번에 하나씩 재귀적으로 수행하는 것입니다.

filter() {
  if [ "$#" -eq 0 ]
  then
    cat
  else
    f="$1"
    shift
    tee >(grep "$f" > "$f") | filter "$@"
  fi
}

printf '%s\n' {foo,bar}{0..100} | filter foo bar r3

그러나 이렇게 하면 추가 버퍼링과 단계가 많이 추가되므로 아껴서 사용하는 것이 좋습니다 eval. 파일 이름이 조심스럽게 이스케이프되므로 괜찮습니다.

filter() {
   cmd="tee "
   for f in "$@"
   do
     cmd+=">(grep -e ${f@Q} > ${f@Q}) "
   done
   eval "$cmd"
}

답변2

당신은 이것을 할 수 있습니다 eval:

# usage xfilter filter_spec filter_args...
xfilter() {
    local cmd flt=$1; shift
    printf -v cmd " >($flt)" "$@"
    eval "tee $cmd"
    wait
}

$ echo paa | xfilter 'sed %q' s/a/e/g s/a/o/g
paa
pee
poo

$ tgrep(){ grep "$1" > "./$1"; }
$ printf '%s\n' foo bar | xfilter 'tgrep %q' foo bar
foo
bar
$ grep . foo bar
foo:foo
bar:bar

아니요, 더 있습니다완전히 괜찮아그리고 eval현명하게 사용한다면. 결국 bash는 eval스크립트의 각 줄을 개별적으로 호출하므로 잠시 생각해보세요.

관련 정보