带数组输入和输出的Bash函数 [英] Bash function with an array input and output

查看:101
本文介绍了带数组输入和输出的Bash函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



  a =()
a + =(A )
a + =(B)
a + =(C)

我可以按照预期进行交互:

  echo$ {a [0]}
# A

echo$ {a [1]}
#返回B

但是当我通过函数运行同一个数组时,我必须做一些错误的事情。首先,我将定义我的函数:

$ p $ 函数sort_array {
declare -a array =($ {! 1})
本地排序=()

排序+ =(1)
排序+ =(2)
排序+ =(3)
$ b $ echo$ {sorted [@]}
}



<现在让我们调用它并检查结果:

  b =()
b = $(sort_array a [@ ])
echo$ {b [0]}

#返回1 2 3
#但是我期待b [0] == 1

我做错了什么?我意识到我的例子可以完全删除函数参数,但我的最终目标是编写一个bash sort_array()函数,我可以传递一个数组并返回一个数组。

解决方案

正如@chepner所说,bash没有数组值。当你将一个数组传递给函数时,你真正在做的是将数组的每个元素作为一个单独的参数传递给该函数。

所有shell函数都可以是 return 是一个单字节的退出代码值,0-255。它们可以返回任何其他东西的唯一方式是使用 echo printf 来输出管他呢;那么调用者必须以任何常用方式捕获输出(命令替换,进程替换,重定向到要读取的文件等)。

也就是说,你的如果你只是给调用添加了一些语法,原代码就可以工作:

  b =($(sort_array$ {a [@]}))

但是,这依赖于有序数组的元素是解析字符串作为单个词。一个更安全的版本是改变 sort_array 函数在每行打印一个元素;调用者可以使用 mapfile builtin(别名 readarray ;需要Bash 4.x)。这看起来像这样:



$ $ p $ 函数sort_array {
declare -a array =($ @)
本地排序=()

排序+ =(1)
排序+ =(2)
排序+ =(3)

printf'%s\\\
'$ {sorted [@]}
}
mapfile -tb< <(sort_array$ {a [@]})

读取数组<(...)中的命令输出中的code> b ; -t 告诉它不要在数组值中包含换行符。



更安全的是使用null字符而不是换行符;最简单的,如果你有bash 4.4,它增加了一个选项 mapfile 来使用不同的字符来代替换行符:

函数sort_array {
declare -a array =($ @)
本地排序=()

排序+ =(1 )
sort + =(2)
sort + =(3)

printf'%s\ 0'$ {sorted [@]}
}
mapfile -t -d'\0'b< <(sort_array$ {a [@]})


If I define an array in bash shell:

a=()
a+=("A")
a+=("B")
a+=("C")

I can interact with it as expected:

echo "${a[0]}"
# Returns "A"

echo "${a[1]}"
# Returns "B"

But when I run that same array through a function, I must be do something wrong. First, I'll define my function:

function sort_array {
  declare -a array=("${!1}")
  local sorted=()

  sorted+=("1")
  sorted+=("2")
  sorted+=("3")

  echo "${sorted[@]}"
}

Now let's call it and inspect the results:

b=()
b=$(sort_array a[@])
echo "${b[0]}"

# Returns "1 2 3"
# But I'm expecting b[0] == 1

What am I doing wrong? I realize my example could remove the function parameter entirely, but my end goal is to write a bash sort_array() function that I can pass an array to and get an array back for.

解决方案

As @chepner said, bash doesn't have array values. When you pass an array to a function, what you're really doing is passing each element of the array as a separate argument to that function.

All shell functions can ever return is a one-byte exit code value, 0-255. The only way they can return anything else is to output it, with echo or printf or whatever; the caller then has to capture that output in any of the usual ways (command substitution, process substitution, redirection into a file to read, etc).

That said, your original code would work if you just added a bit of syntax to the call:

b=($(sort_array "${a[@]}"))

But that relies on the elements of the sorted array being strings that parse as individual words. A safer version would be to change the sort_array function to print out one element per line; the caller can then read those lines into an array using the mapfile builtin (alias readarray; requires Bash 4.x). That looks something like this:

function sort_array {
  declare -a array=("$@")
  local sorted=()

  sorted+=("1")
  sorted+=("2")
  sorted+=("3")

  printf '%s\n' "${sorted[@]}"
}
mapfile -t b < <(sort_array "${a[@]}")

That says to read the array b from the output of the command inside <(...); the -t tells it not to include the newlines in the array values.

Even safer would be to use null characters instead of newlines; easiest if you have bash 4.4 which added an option to mapfile to use a different character in lieu of newline:

function sort_array {
  declare -a array=("$@")
  local sorted=()

  sorted+=("1")
  sorted+=("2")
  sorted+=("3")

  printf '%s\0' "${sorted[@]}"
}
mapfile -t -d '\0' b < <(sort_array "${a[@]}")

这篇关于带数组输入和输出的Bash函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆