Bash : 함수를 매개 변수로 전달


91

Bash에서 매개 변수로 함수를 전달해야합니다. 예를 들어, 다음 코드 :

function x() {
  echo "Hello world"
}

function around() {
  echo "before"
  eval $1
  echo "after"
}

around x

다음을 출력해야합니다.

before
Hello world
after

나는 eval그 맥락에서 정확하지 않다는 것을 알고 있지만 그것은 단지 예일뿐입니다. :)

어떤 생각?

답변:


126

함수 이름이나 인수의 평가를 지연시키는 것과 같은 멋진 것이 필요하지 않다면 다음이 필요하지 않습니다 eval.

function x()      { echo "Hello world";          }
function around() { echo before; $1; echo after; }

around x

당신이 원하는 것을합니다. 다음과 같이 함수와 인수를 전달할 수도 있습니다.

function x()      { echo "x(): Passed $1 and $2";  }
function around() { echo before; "$@"; echo after; }

around x 1st 2nd

인쇄물

before
x(): Passed 1st and 2nd
after

2
다른 y () 함수가 있으면 x 1st 2nd y 1st 2nd 주위에서 할 수 있습니까? x와 y가 주위에 대한 인수이고 1st와 2nd가 x와 y에 대한 인수임을 어떻게 알 수 있습니까?
techguy2000

그리고 기능어를 생략 할 수 있습니다.
jasonleonhard

그러나 이름 간격이 지정되지 않습니다. 즉, 메서드 내부에 메서드가 있고 function단어를 유지하면 최상위 메서드를 실행할 때까지 이러한 내부 메서드에 액세스 할 수 없습니다.
jasonleonhard

29

질문에 답한 사람은 없다고 생각합니다. 그는 순서대로 문자열을 에코 할 수 있는지 묻지 않았습니다. 오히려 질문의 작성자는 함수 포인터 동작을 시뮬레이션 할 수 있는지 알고 싶어합니다.

내가했던 것과 매우 유사한 몇 가지 답변이 있으며 다른 예를 통해 확장하고 싶습니다.

저자로부터 :

function x() {
  echo "Hello world"
}

function around() {
  echo "before"
  ($1)                   <------ Only change
  echo "after"
}

around x

이를 확장하기 위해 함수 x echo "Hello world : $ 1"함수 실행이 실제로 발생하는시기를 표시합니다. 함수 "x"의 이름 인 문자열을 전달합니다.

function x() {
  echo "Hello world:$1"
}

function around() {
  echo "before"
  ($1 HERE)                   <------ Only change
  echo "after"
}

around x

이를 설명하기 위해 문자열 "x"가 "before"를 에코하는 around () 함수에 전달되고, 인수 "HERE"를 전달하는 x 함수 (변수 $ 1, 주위에 전달 된 첫 번째 매개 변수를 통해)를 호출하고, 마지막으로 이후에 에코됩니다. .

다른 방법으로는 변수를 함수 이름으로 사용하는 방법입니다. 변수는 실제로 함수의 이름 인 문자열을 보유하고 ($ variable arg1 arg2 ...) 인수를 전달하는 함수를 호출합니다. 아래를 참조하십시오.

function x(){
    echo $3 $1 $2      <== just rearrange the order of passed params
}

Z="x"        # or just Z=x

($Z  10 20 30)

30 10 20, 여기서 변수 Z에 저장된 "x"라는 함수를 실행하고 매개 변수 10 20 및 30을 전달했습니다.

함수 이름을 실제로 아는 대신 변수를 사용할 수 있도록 함수에 변수 이름을 할당하여 함수를 참조합니다 (이는 프로그램 흐름을 일반화하기 위해 c에서 매우 고전적인 함수 포인터 상황에서 수행 할 수있는 작업과 유사하지만 -명령 줄 인수를 기반으로 할 함수 호출 선택).

bash에서는 함수 포인터가 아니라 나중에 사용하는 함수 이름을 참조하는 변수입니다.


이 대답은 굉장합니다. 모든 예제의 bash 스크립트를 만들어 실행했습니다. 나는 또한 당신이 많은 도움을 준 "변화 만"의 제작자를 만드는 방법을 정말 좋아합니다. 마지막 단락에 두 번째는 잘못된 맞춤법을 가지고 : "Aabove을"
JMI MADISON에게

오타가 수정되었습니다. 감사합니다 @J MADISON
uDude

7
왜 그것을 감싸면 ()하위 쉘이 시작되지 않습니까?
horseyguy

17

사용할 필요가 없습니다 eval

function x() {
  echo "Hello world"
}

function around() {
  echo "before"
  var=$($1)
  echo "after $var"
}

around x

5

문자열 이외의 함수에는 어떤 것도 전달할 수 없습니다. 프로세스 대체는 일종의 가짜 일 수 있습니다. Bash는 확장 된 명령이 완료 될 때까지 FIFO를 열어 두는 경향이 있습니다.

여기에 빠른 어리석은 것입니다

foldl() {
    echo $(($(</dev/stdin)$2))
} < <(tr '\n' "$1" <$3)

# Sum 20 random ints from 0-999
foldl + 0 <(while ((n=RANDOM%999,x++<20)); do echo $n; done)

함수를 내보낼 수 있지만 처음 나타나는 것만 큼 흥미롭지는 않습니다. 주로 스크립트를 실행하는 스크립트 나 다른 프로그램에 액세스 할 수있는 디버깅 기능을 만드는 데 유용합니다.

(
    id() {
        "$@"
    }

    export -f id
    exec bash -c 'echowrap() { echo "$1"; }; id echowrap hi'
)

id 여전히 함수의 이름 인 문자열 (환경의 직렬화에서 자동으로 가져옴)과 해당 인수 만 가져옵니다.

다른 답변에 대한 Pumbaa80의 의견도 좋지만 ( eval $(declare -F "$1")), 항상 전역이기 때문에 함수가 아닌 배열에 주로 유용합니다. 함수 내에서 이것을 실행한다면 재정의 만하면되므로 효과가 없습니다. 현재 스코프에서 어떤 일이 발생 하느냐에 따라 클로저 나 부분 함수 또는 "함수 인스턴스"를 만드는 데 사용할 수 없습니다. 기껏해야 이것은 다른 곳에서 재정의되는 문자열에 함수 정의를 저장하는 데 사용할 수 있습니다. 그러나 이러한 함수는 물론 eval사용 되지 않는 한 하드 코딩 될 수도 있습니다.

기본적으로 Bash는 이렇게 사용할 수 없습니다.


2

더 나은 방법은 함수에 지역 변수를 사용하는 것입니다. 그러면 문제는 호출자에게 결과를 어떻게 얻을 수 있는가가됩니다. 한 가지 메커니즘은 명령 대체를 사용하는 것입니다.

function myfunc()
{
    local  myresult='some value'
    echo "$myresult"
}

result=$(myfunc)   # or result=`myfunc`
echo $result

여기서 결과는 stdout에 출력되고 호출자는 명령 대체를 사용하여 변수의 값을 캡처합니다. 그런 다음 필요에 따라 변수를 사용할 수 있습니다.


1

다음과 같은 내용이 있어야합니다.

function around()
{
  echo 'before';
  echo `$1`;
  echo 'after';
}

그런 다음 전화 할 수 있습니다. around x


-1

eval은이를 달성하는 유일한 방법 일 것입니다. 유일한 단점은 악의적 인 것이 전달되지 않고 호출하려는 함수 만 호출되도록해야하기 때문에 보안 측면입니다 ( ';'와 같은 불쾌한 문자가 없는지 확인하는 것과 함께). 그것도).

따라서 코드를 호출하는 사람이라면 eval이이를 수행하는 유일한 방법 일 것입니다. 하위 명령 ($ () 및``)과 관련하여 너무 작동 할 가능성이있는 다른 형식의 eval이 있지만 더 안전하지 않고 더 비쌉니다.


eval은이를 수행하는 유일한 방법입니다.
Wes

1
다음을 eval $1사용하여 함수를 호출 하는지 쉽게 확인할 수 있습니다.if declare -F "$1" >/dev/null; then eval $1; fi
user123444555621 2011-04-15

2
... 또는 더 나은 :eval $(declare -F "$1")
user123444555621 2011-04-15
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.