将参数传递给Bash函数

时间:2011-06-02 08:35:17

标签: bash

我正在尝试搜索如何在Bash函数中传递参数,但是出现的问题始终是如何从命令行传递参数。

我想在我的脚本中传递参数。我试过了:

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

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

但语法不正确,如何将参数传递给我的函数?

7 个答案:

答案 0 :(得分:1390)

声明函数有两种典型方法。我更喜欢第二种方法。

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

Reference: Advanced Bash-Scripting Guide

答案 1 :(得分:54)

高级编程语言(C / C ++ / Java / PHP / Python / Perl ...)的知识会向外行人建议bash函数应该像在其他语言中那样工作。 而不是,bash函数就像shell命令一样工作,并希望将参数传递给它们的方式与将命令传递给shell命令(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

答案 2 :(得分:37)

如果您更喜欢命名参数,可以(通过一些技巧)将命名参数实际传递给函数(也可以传递数组和引用)。

我开发的方法允许您定义传递给函数的命名参数:

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;'

答案 3 :(得分:26)

错过了parens和逗号:

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

并且函数应该如下所示:

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

答案 4 :(得分:6)

我希望这个例子可以帮到你。它从用户那里获取两个数字,将它们提供给名为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

答案 5 :(得分:4)

我想提到另一种将命名参数传递给bash的方法......通过引用传递。从bash 4.0开始支持此功能

#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>

//Prototyping
int fileNameBegin(const char *a, const char *b);
void returner(char directory[256], char string[32]);
void print();

//Array of Node Pointer
struct node* arrayOfLinkedLists[26];

//Main
int main() {
    printf("Enter Directory Address:\n");
    char str[256];
    gets(str);
    char letter[32];
    do {
        printf("Enter letters to search by:\n");
        letter[0] = '\0';
        gets(letter);
        returner(str, letter);
        print();

    } while (letter[0] != '\0');
    return 0;
}

//Constructing the Node Struct
struct node{
    char fileName[50];
    struct node *next;
};

//Narrowing Down Search
int fileNameBegin(const char *a, const char *b)
{
    if(strncasecmp(a, b, strlen(b)) == 0) return 1; //not case sensitive, string comparing var a and b with String length
    return 0;
}

#define DATA_MAX_LEN    50

//Adding the node (Files) to the LinkedList in Array
void addFileName(struct node **pNode, const char *c)
{
    while (*pNode)
        pNode = &(*pNode)->next; //It equals the address of the pointer

    *pNode = malloc( sizeof **pNode );

    strncpy((*pNode)->fileName,c,DATA_MAX_LEN-1); //Copying characters from String
    (*pNode)->fileName[ DATA_MAX_LEN-1] = 0;
    (*pNode)->next = NULL;
}

//Opening the Directory. Reading from Directory. Comparing File Name to String and Adding if there's a match
void returner(char directory[256], char string[32])
{
    DIR *pDir = opendir (directory);
    if (pDir)
    {
        struct dirent *pent;
        while ((pent = readdir(pDir)))
        {
            if (pent->d_name[0] == '.' && (pent->d_name[1] == 0 || (pent->d_name[1] == '.' && pent->d_name[2] == 0)))
                continue;

            if(fileNameBegin(pent->d_name, string))
                addFileName(arrayOfLinkedLists + ((int) strlwr(string)[0] - 97), pent->d_name);
        }
        closedir (pDir);
    }
}

//I have no idea what this does.... oh, it displays it, duh.
void print(){
    int i;
    struct node *temp;

    for(i=0 ; i < 26; i++){
        temp = arrayOfLinkedLists[i];
        while(temp != NULL){
            printf("%s\n",temp->fileName);
            temp = temp->next;
        }
    }
    free(temp);
}

bash 4.3的另一种语法是使用nameref

虽然nameref更方便,因为它无缝解除引用,但是一些较旧的受支持的发行版仍然发布了older version,所以我还是不推荐它。

答案 6 :(得分:4)

一个简单的例子,在调用函数时将在执行脚本或内部脚本期间清除。

#!/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