Bash 함수에 매개 변수 전달


980

Bash 함수에서 매개 변수를 전달하는 방법을 검색하려고하지만 항상 명령 줄에서 매개 변수를 전달하는 방법이 있습니다.

스크립트 내에서 매개 변수를 전달하고 싶습니다. 나는 시도했다 :

myBackupFunction("..", "...", "xx")

function myBackupFunction($directory, $options, $rootPassword) {
     ...
}

그러나 구문이 올바르지 않습니다. 매개 변수를 함수에 전달하는 방법은 무엇입니까?


6
"...하지만 나타나는 것은 항상 명령 행에서 매개 변수를 전달하는 방법입니다"-예! Bash 스크립트는 기본적으로 일련의 명령 행이기 때문에 Bash 스크립트에서 명령 행의 명령 인 것처럼 함수를 호출하십시오! :-) 전화는 myBackupFunction ".." "..." "xx"입니다. 괄호도없고 쉼표도 없습니다.
Wil

4
이 질문에 대응하는 것 : bash 함수에서 반환 값
MSalters

답변:


1618

함수를 선언하는 일반적인 두 가지 방법이 있습니다. 나는 두 번째 접근법을 선호합니다.

function function_name {
   command...
} 

또는

function_name () {
   command...
} 

인수가있는 함수를 호출하려면

function_name "$arg1" "$arg2"

이 함수는 이름이 아닌 위치에 따라 전달 된 인수, 즉 $ 1, $ 2 등을 나타냅니다. $ 0 은 스크립트 자체의 이름입니다.

예:

function_name () {
   echo "Parameter #1 is $1"
}

또한 함수 가 선언 된 후에 함수를 호출해야합니다 .

#!/usr/bin/env sh

foo 1  # this will fail because foo has not been declared yet.

foo() {
    echo "Parameter #1 is $1"
}

foo 2 # this will work.

산출:

./myScript.sh: line 2: foo: command not found
Parameter #1 is 2

참조 : Advanced Bash-Scripting Guide .


4
공백을 잊어 버렸습니다 function name() {}. 아마 전에 'enter'로{}
lalo

21
좋은 대답입니다. 제 2 센트 : 쉘 구조의 해당 소스로 파일에 상주 (점선) 필요할 때, 내가 사용하는 것을 선호 function키워드 (). (파일이 아닌 명령 줄에서) 내 목표는, 입력 된 문자, 즉의 수를 줄이고, 선명도를하지 증가시키는 것이다 function myBackupFunction() compound-statement.
Terry Gardner

22
@CMCDragonkai, function키워드 버전은 확장입니다. 다른 형식은 모든 POSIX 호환 쉘에서 작동합니다.
Charles Duffy

8
@TerryGardner, 선명도를 높이려는 시도는 호환성을 저하시키는 것으로 생각하십시오.
Charles Duffy

6
@RonBurk, 아마도-그러나 우리가 명확성을 고려하더라도, function키워드는 현대 kbash가 존중하지 않는다는 것을 소개 한 오래된 ksh-family 쉘에서 보장했습니다 (이러한 쉘에서는 function변수를 로컬에서 기본으로; bash에서 그렇지 않습니다). 따라서 ksh 동작을 알고 있고 기대할 수있는 사람에게는 명확성을 떨어 뜨립니다. wiki.bash-hackers.org/scripting/obsolete
Charles Duffy를

68

고급 프로그래밍 언어 (C / C ++ / Java / PHP / Python / Perl ...)에 대한 지식은 일반인에게 bash 함수가 다른 언어에서와 같이 작동해야 함을 제안합니다. 대신 , bash 함수는 쉘 명령처럼 작동하며 옵션을 쉘 명령 (예 :)에 전달할 수있는 것과 같은 방식으로 인수가 전달 될 것으로 예상합니다 ls -l. 실제로 bash의 함수 인수위치 매개 변수 ( $1, $2..$9, ${10}, ${11}등) 로 처리됩니다 . getopts작동 방식을 고려해도 놀라운 일이 아닙니다 . 괄호를 사용하여 bash에서 함수를 호출하지 마십시오.


( 참고 : 현재 Open Solaris에서 작업 중입니다.)

# bash style declaration for all you PHP/JavaScript junkies. :-)
# $1 is the directory to archive
# $2 is the name of the tar and zipped file when all is done.
function backupWebRoot ()
{
    tar -cvf - $1 | zip -n .jpg:.gif:.png $2 - 2>> $errorlog &&
        echo -e "\nTarball created!\n"
}


# sh style declaration for the purist in you. ;-)
# $1 is the directory to archive
# $2 is the name of the tar and zipped file when all is done.
backupWebRoot ()
{
    tar -cvf - $1 | zip -n .jpg:.gif:.png $2 - 2>> $errorlog &&
        echo -e "\nTarball created!\n"
}


# In the actual shell script
# $0               $1            $2

backupWebRoot ~/public/www/ webSite.tar.zip

변수 이름을 사용하려고합니다. 그냥하세요

declare filename=$1 # declare gives you more options and limits variable scope

배열을 함수에 전달하고 싶습니까?

callingSomeFunction "${someArray[@]}" # Expands to all array elements.

함수 내에서 이와 같은 인수를 처리하십시오.

function callingSomeFunction ()
{
    for value in "$@" # You want to use "$@" here, not "$*" !!!!!
    do
        :
    done
}

값과 배열을 전달해야하지만 여전히 함수 내에서 "$ @"를 사용합니까?

function linearSearch ()
{
    declare myVar="$1"

    shift 1 # removes $1 from the parameter list

    for value in "$@" # Represents the remaining parameters.
    do
        if [[ $value == $myVar ]]
        then
            echo -e "Found it!\t... after a while."
            return 0
        fi
    done

    return 1
}

linearSearch $someStringValue "${someArray[@]}"

64

명명 된 매개 변수를 선호하는 경우 실제로 몇 가지 트릭을 사용하여 명명 된 매개 변수를 함수에 전달할 수도 있습니다 (배열과 참조를 전달할 수도 있습니다).

내가 개발 한 방법을 사용하면 다음과 같은 함수에 전달 된 명명 된 매개 변수를 정의 할 수 있습니다.

function example { args : string firstName , string lastName , integer age } {
  echo "My name is ${firstName} ${lastName} and I am ${age} years old."
}

또한 @required 또는 @readonly로 인수에 주석을 달고 ... rest 인수를 작성하고 순차적 인수에서 배열을 작성하고 (예 :를 사용하여 string[4]) 선택적으로 인수를 여러 줄에 나열 할 수 있습니다.

function example {
  args
    : @required string firstName
    : string lastName
    : integer age
    : string[] ...favoriteHobbies

  echo "My name is ${firstName} ${lastName} and I am ${age} years old."
  echo "My favorite hobbies include: ${favoriteHobbies[*]}"
}

다시 말해, 이름으로 매개 변수를 호출 할 수있을뿐만 아니라 (더 읽기 쉬운 코어를 구성 함) 실제로 배열을 전달할 수 있습니다 (변수에 대한 참조-이 기능은 bash 4.3에서만 작동합니다). 또한 매핑 된 변수는 모두 $ 1 (및 기타)과 같이 로컬 범위에 있습니다.

이 작업을 수행하는 코드는 매우 가볍고 bash 3 및 bash 4에서 모두 작동합니다 (이것은 내가 테스트 한 유일한 버전입니다). bash로 개발하는 것을 훨씬 더 좋고 쉽게 만드는 더 많은 트릭에 관심이 있다면 내 Bash Infinity Framework를 살펴보십시오. 아래 코드는 기능 중 하나입니다.

shopt -s expand_aliases

function assignTrap {
  local evalString
  local -i paramIndex=${__paramIndex-0}
  local initialCommand="${1-}"

  if [[ "$initialCommand" != ":" ]]
  then
    echo "trap - DEBUG; eval \"${__previousTrap}\"; unset __previousTrap; unset __paramIndex;"
    return
  fi

  while [[ "${1-}" == "," || "${1-}" == "${initialCommand}" ]] || [[ "${#@}" -gt 0 && "$paramIndex" -eq 0 ]]
  do
    shift # first colon ":" or next parameter's comma ","
    paramIndex+=1
    local -a decorators=()
    while [[ "${1-}" == "@"* ]]
    do
      decorators+=( "$1" )
      shift
    done

    local declaration=
    local wrapLeft='"'
    local wrapRight='"'
    local nextType="$1"
    local length=1

    case ${nextType} in
      string | boolean) declaration="local " ;;
      integer) declaration="local -i" ;;
      reference) declaration="local -n" ;;
      arrayDeclaration) declaration="local -a"; wrapLeft= ; wrapRight= ;;
      assocDeclaration) declaration="local -A"; wrapLeft= ; wrapRight= ;;
      "string["*"]") declaration="local -a"; length="${nextType//[a-z\[\]]}" ;;
      "integer["*"]") declaration="local -ai"; length="${nextType//[a-z\[\]]}" ;;
    esac

    if [[ "${declaration}" != "" ]]
    then
      shift
      local nextName="$1"

      for decorator in "${decorators[@]}"
      do
        case ${decorator} in
          @readonly) declaration+="r" ;;
          @required) evalString+="[[ ! -z \$${paramIndex} ]] || echo \"Parameter '$nextName' ($nextType) is marked as required by '${FUNCNAME[1]}' function.\"; " >&2 ;;
          @global) declaration+="g" ;;
        esac
      done

      local paramRange="$paramIndex"

      if [[ -z "$length" ]]
      then
        # ...rest
        paramRange="{@:$paramIndex}"
        # trim leading ...
        nextName="${nextName//\./}"
        if [[ "${#@}" -gt 1 ]]
        then
          echo "Unexpected arguments after a rest array ($nextName) in '${FUNCNAME[1]}' function." >&2
        fi
      elif [[ "$length" -gt 1 ]]
      then
        paramRange="{@:$paramIndex:$length}"
        paramIndex+=$((length - 1))
      fi

      evalString+="${declaration} ${nextName}=${wrapLeft}\$${paramRange}${wrapRight}; "

      # continue to the next param:
      shift
    fi
  done
  echo "${evalString} local -i __paramIndex=${paramIndex};"
}

alias args='local __previousTrap=$(trap -p DEBUG); trap "eval \"\$(assignTrap \$BASH_COMMAND)\";" DEBUG;'

무엇입니까 @var, @reference, @params변수는? 이에 대해 더 배우려면 인터넷에서 무엇을 찾아봐야합니까?
GypsyCosmonaut

3
좋은 답변입니다! 방금 Bash Infinity를 연구했는데 실제로 도움이 될 것 같습니다. 감사!
Jonathan Hult

감사합니다 @JonathanHult! 실제로 최근에 위의 답변을 업데이트했으며 이제는 현재 Bash Infinity 2.0에있는 코드에 대해 새롭고 재 작성되었습니다. 내가 다시 쓴 이유는 이전 구현의 버그 때문입니다 (GitHub의 문제에 있음). 새 버전을 Bash Infinity에 다시 통합 할 시간이 없었습니다. 도움이되었다 니 다행입니다.
niieani

안녕 @niieani 대답에 사용하는 형식으로 bash 함수를 만들려고하면 apt에서 ucommon utils를 설치해야한다고 알려줍니다. 이것이 bash 스크립트 작동 방식입니까? 내가 올바르게하고 있습니까? 내가 당신이나 다른 누군가가 기본적으로 Bash의 확장을 허용하기 위해 ucommon util 프로그램을 구축했다는 것을 이해한다면 맞습니까?
David A. French

@ DavidA.French 아니오, 이것은 일어나지 않아야합니다. ucommon와 내 코드 사이에는 아무런 관계가 없습니다 . 언급 한 문제를 일으키는 도구가 설치되어있을 수 있습니다. 무엇이 될 수 있는지 모릅니다.
niieani

27

괄호와 쉼표를 놓치십시오.

 myBackupFunction ".." "..." "xx"

함수는 다음과 같아야합니다.

function myBackupFunction() {
   # here $1 is the first parameter, $2 the second etc.
}

8

이 예제가 도움이되기를 바랍니다. 사용자로부터 두 개의 숫자를 가져 와서 add(코드의 마지막 줄에서) 호출 된 함수에 공급하고 add합계하여 인쇄합니다.

#!/bin/bash

read -p "Enter the first  value: " x
read -p "Enter the second value: " y

add(){
    arg1=$1 #arg1 gets to be the first  assigned argument (note there are no spaces)
    arg2=$2 #arg2 gets to be the second assigned argument (note there are no spaces)

    echo $(($arg1 + $arg2))
}

add x y #feeding the arguments

6
그런 식으로 이름으로 전달하면 숫자 연산자 (())로 전달 된 정수에만 작동하며 숫자 연산자는 문자열을 반복적으로 값으로 해석하기 때문에 작동합니다. 내가 의미하는 바를 테스트하려면 x에 '5'를 입력하고 y에 'x'를 입력하면 (x + y) = (5 + x) = (5 + 5)가 추가됩니다. = 10. 다른 모든 사용 사례의 경우 예제가 실패합니다. 대신 일반 코드에 'add "$ x" "$ y"'를 사용해야합니다.
Wil

6

스크립트를 실행하는 동안 또는 함수를 호출하는 동안 내부 스크립트를 모두 지우는 간단한 예입니다.

#!/bin/bash
echo "parameterized function example"
function print_param_value(){
    value1="${1}" # $1 represent first argument
    value2="${2}" # $2 represent second argument
    echo "param 1 is  ${value1}" #as string
    echo "param 2 is ${value2}"
    sum=$(($value1+$value2)) #process them as number
    echo "The sum of two value is ${sum}"
}
print_param_value "6" "4" #space sparted value
#you can also pass paramter durign executing script
print_param_value "$1" "$2" #parameter $1 and $2 during executing

#suppose our script name is param_example
# call like this 
# ./param_example 5 5
# now the param will be $1=5 and $2=5

5

명명 된 매개 변수를 bash에 전달하는 다른 방법을 언급하면서 참조로 전달한다고 생각했습니다. 이것은 bash 4.0부터 지원됩니다

#!/bin/bash
function myBackupFunction(){ # directory options destination filename
local directory="$1" options="$2" destination="$3" filename="$4";
  echo "tar cz ${!options} ${!directory} | ssh root@backupserver \"cat > /mnt/${!destination}/${!filename}.tgz\"";
}

declare -A backup=([directory]=".." [options]="..." [destination]="backups" [filename]="backup" );

myBackupFunction backup[directory] backup[options] backup[destination] backup[filename];

bash 4.3의 다른 구문은 nameref를 사용하는 것입니다

nameref가 완벽하게 역 참조된다는 점에서 훨씬 편리하지만, 일부 이전 지원되는 배포판은 여전히 이전 버전을 제공 하므로 아직 권장하지 않습니다.


"파이프 인". 난 당신이 무슨 짓을했는지 참조!
잭 토스
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.