繁体   English   中英

将参数传递给 Bash function

[英]Passing parameters to a Bash function

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

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

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

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

但是语法不正确。 如何将参数传递给我的 function?

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

function function_name {
   command...
} 

或者

function_name () {
   command...
} 

要使用 arguments 调用 function:

function_name "$arg1" "$arg2"

function 是指通过他们的 position (不是名称)传递的 arguments ,即$1$2等等。 $0是脚本本身的名称。

例子:

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

此外,您需要在声明调用您的 function。

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

Output:

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

参考:高级 Bash 脚本指南

Knowledge of high level programming languages (C/C++, Java, PHP, Python, Perl, etc.) would suggest to the layman that Bourne Again Shell (Bash) functions should work like they do in those other languages.

Instead , Bash functions work like shell commands and expect arguments to be passed to them in the same way one might pass an option to a shell command (eg ls -l ). 实际上, Bash中的 function arguments 被视为位置参数$1, $2..$9, ${10}, ${11}等), 考虑到getopts的工作原理,这并不奇怪。 不要使用括号来调用 Bash 中的 function。


注意:我现在正好在OpenSolaris上工作。)

# 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

想要为变量使用名称? 就做这件事。

local filename=$1 # The keyword declare can be used, but local is semantically more specific.

不过要小心。 如果 function 的参数中有一个空格,您可能想要这样做,否则, $1可能不是您认为的那样。

local filename="$1" # Just to be on the safe side. Although, if $1 was an integer, then what? Is that even possible? Humm.

想要将数组传递给 function?

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

在 function 内部,像这样处理 arguments。

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

需要传递一个值和一个数组,但仍然在 function 内部使用“$@”?

function linearSearch ()
{
    local 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[@]}"

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

我开发的方法允许您定义传递给 function 的命名参数,如下所示:

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

You can also annotate arguments as @required or @readonly, create...rest arguments, create arrays from sequential arguments (using eg string[4] ) and optionally list the arguments in multiple lines:

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[*]}"
}

换句话说,您不仅可以通过参数名称调用参数(这构成了更易读的核心),您实际上可以传递 arrays (以及对变量的引用 - 此功能仅适用于 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 parameter:
      shift
    fi
  done
  echo "${evalString} local -i __paramIndex=${paramIndex};"
}

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

去掉括号和逗号:

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

function 应该如下所示:

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

它从用户那里获取两个数字,将它们提供给名为add的 function(在代码的最后一行),然后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

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

#!/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-separated value
# You can also pass parameters during executing the script
print_param_value "$1" "$2" # Parameter $1 and $2 during execution

# Suppose our script name is "param_example".
# Call it like this:
#
# ./param_example 5 5
#
# Now the parameters will be $1=5 and $2=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 更方便,因为它可以无缝取消引用,但一些受支持的旧发行版仍然提供旧版本,所以我暂时不推荐它。

有什么想法让这个与导出的函数一起工作吗?

$cat /tmp/test.sh
#!/bin/bash -ue

function doit() {

    echo "Args are $@"

    for d in $@
    do
    echo "Arg=$d"
    
    done
}


doit a b c

doit $@

export -f doit

bash -c doit ext1 ext2 ext3

$ bash /tmp/test.sh  tom dick harry
Args are a b c
Arg=a
Arg=b
Arg=c
Args are tom dick harry
Arg=tom
Arg=dick
Arg=harry
Args are 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM