Bash连接数组条目,中间没有空格

时间:2022-05-22 16:51:30

Problem

问题

I'm writing an bash script (version 4.3.48). There I have an array and want to concatenate all entries as a single string. The following code do such task (but lag in some case):

我正在编写一个bash脚本(版本4.3.48)。我有一个数组,并希望将所有条目连接为一个字符串。以下代码执行此类任务(但在某些情况下滞后):

declare -a array=(one two three)
echo "${array[@]}"

Unfortunately I get this output, including spaces in between the array entries:

不幸的是我得到了这个输出,包括数组条目之间的空格:

one two three

But what I actually need is this:

但我真正需要的是:

onetwothree


Background

背景

I try to avoid using a for-loop and concatenate it on my own, cause I call this very often (more than each second) and I guess such a loop is much more expensive than use a build-in function.

我试图避免使用for循环并自己连接它,因为我经常调用它(超过每秒)并且我猜这样的循环比使用内置函数要昂贵得多。

So any suggestions how to obtain the required result?

那么任何建议如何获得所需的结果?

2 个解决方案

#1


5  

printf gives you a lot more control over formatting, and it is also a bash builtin:

printf为您提供了更多的格式控制,它也是一个内置的bash:

printf %s "${array[@]}" $'\n'

(That works because the shell's printf keeps on repeating the pattern until the arguments are all used up.)

(这是有效的,因为shell的printf继续重复模式,直到参数全部用完为止。)

#2


2  

First, that's the wrong way to initialize an array:

首先,这是初始化数组的错误方法:

$ declare -A array=( one two three )
bash: array: one: must use subscript when assigning associative array
bash: array: two: must use subscript when assigning associative array
bash: array: three: must use subscript when assigning associative array

declare -A is for associative arrays. Just do this

declare -A用于关联数组。就这样做吧

$ array=( one two three )
$ declare  -p array
declare -a array='([0]="one" [1]="two" [2]="three")'

You want to use the * subscript instead of @. That joins the array elements using the first character of the IFS array. If you don't want any separator, assign the empty string to IFS. Since lots of things depend on IFS, I typically use a subshell to contain the modifications:

您想使用*下标而不是@。它使用IFS数组的第一个字符连接数组元素。如果您不想要任何分隔符,请将空字符串分配给IFS。由于很多东西都依赖于IFS,我通常使用子shell来包含修改:

$ (IFS=; echo "${array[*]}")
onetwothree

To assign the result to a variable, it's the usual command substitution syntax:

要将结果分配给变量,它是通常的命令替换语法:

$ joined=$(IFS=; echo "${array[*]}"); echo "$joined"
onetwothree

And we can see that the IFS value in this shell (space, tab, newline) is unchanged:

我们可以看到此shell中的IFS值(空格,制表符,换行符)未更改:

$ printf "%s" "$IFS" | od -c
0000000      \t  \n
0000003

If performance is a goal and you want to avoid spawning a subshell, use a function:

如果性能是目标,并且您希望避免产生子shell,请使用以下函数:

$ concat_array() { local -n a=$1; local IFS=; echo "${a[*]}"; }
$ concat_array array
onetwothree

with bash version older than 4.3, use an indirect variable instead of a nameref

使用早于4.3的bash版本,使用间接变量而不是nameref

$ concat_array() { local tmp="${1}[*]"; local IFS=; echo "${!tmp}"; }

#1


5  

printf gives you a lot more control over formatting, and it is also a bash builtin:

printf为您提供了更多的格式控制,它也是一个内置的bash:

printf %s "${array[@]}" $'\n'

(That works because the shell's printf keeps on repeating the pattern until the arguments are all used up.)

(这是有效的,因为shell的printf继续重复模式,直到参数全部用完为止。)

#2


2  

First, that's the wrong way to initialize an array:

首先,这是初始化数组的错误方法:

$ declare -A array=( one two three )
bash: array: one: must use subscript when assigning associative array
bash: array: two: must use subscript when assigning associative array
bash: array: three: must use subscript when assigning associative array

declare -A is for associative arrays. Just do this

declare -A用于关联数组。就这样做吧

$ array=( one two three )
$ declare  -p array
declare -a array='([0]="one" [1]="two" [2]="three")'

You want to use the * subscript instead of @. That joins the array elements using the first character of the IFS array. If you don't want any separator, assign the empty string to IFS. Since lots of things depend on IFS, I typically use a subshell to contain the modifications:

您想使用*下标而不是@。它使用IFS数组的第一个字符连接数组元素。如果您不想要任何分隔符,请将空字符串分配给IFS。由于很多东西都依赖于IFS,我通常使用子shell来包含修改:

$ (IFS=; echo "${array[*]}")
onetwothree

To assign the result to a variable, it's the usual command substitution syntax:

要将结果分配给变量,它是通常的命令替换语法:

$ joined=$(IFS=; echo "${array[*]}"); echo "$joined"
onetwothree

And we can see that the IFS value in this shell (space, tab, newline) is unchanged:

我们可以看到此shell中的IFS值(空格,制表符,换行符)未更改:

$ printf "%s" "$IFS" | od -c
0000000      \t  \n
0000003

If performance is a goal and you want to avoid spawning a subshell, use a function:

如果性能是目标,并且您希望避免产生子shell,请使用以下函数:

$ concat_array() { local -n a=$1; local IFS=; echo "${a[*]}"; }
$ concat_array array
onetwothree

with bash version older than 4.3, use an indirect variable instead of a nameref

使用早于4.3的bash版本,使用间接变量而不是nameref

$ concat_array() { local tmp="${1}[*]"; local IFS=; echo "${!tmp}"; }