인수와 함께 명령을 전달하고 함수로 리디렉션

인수와 함께 명령을 전달하고 함수로 리디렉션

Bash 스크립트에서는 매개변수와 함께 명령을 전달합니다. 명령에 리디렉션이 포함되어 있지 않으면 제대로 작동합니다. 이 경우 리디렉션 문자는 일반 문자로 처리됩니다.

$ cat foo
#!/bin/bash

f() {
  echo "command: $@"
  $@
}

f echo a-one a-two
f 'echo b-one b-two'
f 'echo c-one c-two > c.tmp'
# I don't want to do f echo d-one d-two > d.tmp because I want to redirect the
# output of the passed command, not the output of the f() function.

$ ./foo
command: echo a-one a-two
a-one a-two
command: echo b-one b-two
b-one b-two
command: echo c-one c-two > c.tmp
c-one c-two > c.tmp

보시다시피 "c-one c-two"를 c.tmp 파일에 인쇄하려고 하면 "c-one c-two > c.tmp"가 인쇄됩니다. 이를 수행할 수 있는 방법이 있습니까?

답변1

f() {
  echo "command: $@"
  $@
}

일반적으로 말하자면, 당신은사용해야한다"$@", 여기도 있어요대개 이유.

그러나 당신 말이 맞습니다. 이와 같은 명령을 실행하면 쉘 연산자가 처리되지 않으며 리디렉션 이나 &&.eval

특히 임의의 파일 이름을 전달하는 것이 다시 어려워집니다. 예를 들어, 이는 궁극적으로 다음 ls두 파일에서 실행 됩니다 foo.bar

run_with_eval() {
    eval "$@"
}
file='foo bar'
run_with_eval ls -l "$file" 

당신은해야합니다참조할 파일 이름 정렬이는 쉘에 약간 어색하고 오류가 발생하기 쉽습니다.

하지만 만약 당신이오직리디렉션하거나 더 나은 방법으로 출력 전용 리디렉션을 수행하려면 >함수가 이를 수동으로 처리하도록 할 수 있습니다.

#!/bin/bash
run_with_redir() {
    local redir=
    if [[ $1 = '>' ]]; then
        redir=$2
        shift 2
    fi
    ## whatever else you do
    if [[ $redir ]]; then
        "$@" > "$redir"
    else
        "$@"
    fi
}

run_with_redir echo "normal command, no redirection"
run_with_redir ">" output.txt echo "this gets redirected to output.txt"

즉, >파일 이름을 처음 두 개의 인수로 사용하여 함수를 호출하고, 나머지 인수를 명령으로 실행하고, 출력을 리디렉션합니다. 그렇지 않은 경우 >정상적으로 명령을 실행합니다. ">"함수를 호출할 때 따옴표를 넣어야 합니다. 그렇지 않으면 전체 함수의 출력 리디렉션이 다시 발생합니다 . 예를 들어 이를 지원하기 위해 확장하는 것은 >>중복이더라도 사소한 일입니다.

이는 더 까다로운 경우에도 작동합니다.

run_with_redir ">" "output file with space.txt" ls -l "other file with space"

답변2

eval "$@"작업을 수행합니다:

#!/bin/bash

f() {
  echo "command: $@"
  eval "$@"
}

하지만 일반적으로 보더라도 사용하기에는 매우 안전하지 않습니다. 여기 저기에.

답변3

eval을 사용하지 않는 방법이지만 매우 안전하지도 않습니다.

#!/bin/bash

f() {
  echo "command: $@"
  bash -c "$@"
}

f echo a-one a-two
f 'echo b-one b-two'
f 'echo c-one c-two > c.tmp'

관련 정보