在bash中将数组转换为字符串
1. 使用$IFS
将数组转换为字符串
因为括号用于界定一个数组,而不是一个字符串:
ids="1 2 3 4";echo ${ids// /|}
1|2|3|4
一些示例:使用两个字符串填充
$ids
:
a b
和
c d
ids=("a b" "c d" e\ f)
echo ${ids[*]// /|}
a|b c|d e|f
IFS='|';echo "${ids[*]}";IFS=$' \t\n'
a b|c d|e f
...最后:
IFS='|';echo "${ids[*]// /|}";IFS=$' \t\n'
a|b|c|d|e|f
将数组组装在一起,以$IFS
的第一个字符分隔,但是在数组的每个元素中将空格替换为|
。
当你执行以下操作时:
id="${ids[@]}"
你将由合并数组ids的字符串构建的字符串通过空格转移到一个新的字符串类型的变量中。
注意:当"${ids[@]}"给出一个以空格分隔的字符串时,"${ids[*]}"(用星号*代替at符号@)将会生成一个由$IFS的第一个字符分隔的字符串。
"man bash"的解释如下:
man -Len -Pcol\ -b bash | sed -ne '/^ *IFS /{N;N;p;q}'
IFS The Internal Field Separator that is used for word splitting
after expansion and to split lines into words with the read
builtin command. The default value is ``<space><tab><newline>''.
玩弄
$IFS
:
printf "%q\n" "$IFS"
$' \t\n'
字面上是一个空格、一个制表符和一个换行符。所以,虽然第一个字符是一个空格,但使用 * 与 @ 的效果是相同的。
但是:
{
IFS=: read -a array < <(echo root:x:0:0:root:/root:/bin/bash)
echo 1 "${array[@]}"
echo 2 "${array[*]}"
OIFS="$IFS" IFS=:
echo 3 "${array[@]}"
echo 4 "${array[*]}"
IFS="$OIFS"
}
1 root x 0 0 root /root /bin/bash
2 root x 0 0 root /root /bin/bash
3 root x 0 0 root /root /bin/bash
4 root:x:0:0:root:/root:/bin/bash
注意:行
IFS=: read -a array < <(...)
将使用
:
作为分隔符,而不会永久设置
$IFS
。这是因为输出行
#2
以空格作为分隔符。
1.1 使用函数
localize $IFS
只需打印数组
printArry() {
local IFS="$1"
shift
echo "$*"
}
printArry @ "${ids[@]}"
a b@c d@e f
或者在原地合并数组。
mergeArry() {
local IFS="$1"
local -n _array_to_merge=$2
_array_to_merge=("${_array_to_merge[*]}")
}
declare -p ids
declare -a ids=([0]="a b" [1]="c d" [2]="e f")
mergeArry '#' ids
declare -p ids
declare -a ids=([0]="a b#c d#e f")
2. 字符串数组转字符串数组([@]
vs [*]
)
这里有一个明显的区别:
"$@"
和 "${var[@]}"
会生成一个字符串数组
"$*"
和 "${var[*]}"
会生成一个唯一的字符串
请仔细阅读:man '-Pless +/Special\ Parameters' bash
为了实现这个目的,我将引用每个参数,以防止在命令行扩展时被$IFS
分割,使用双引号来允许变量扩展。
ids=('a b c' 'd e f' 'g h i')
printf '<< %s >>\n' "${ids[@]// /|}"
<< a|b|c >>
<< d|e|f >>
<< g|h|i >>
printf '<< %s >>\n' "${ids[*]// /|}"
<< a|b|c d|e|f g|h|i >>
在哪里:
- 所有空格都被管道符替换,每个字符串中都是如此
- 所有字符串都合并为一个字符串,由第一个
$IFS
字符分隔。
( IFS='@'; printf '<< %s >>\n' "${ids[*]// /|}" )
<< a|b|c@d|e|f@g|h|i >>
注意:`
${var// /something}
`将会用`
something`替换每一个空格,但是`
${var[*]}
`将会通过只使用第一个字符来合并数组。
( IFS='FOO'; printf '<< %s >>\n' "${ids[*]// / BAR }" )
<< a BAR b BAR cFd BAR e BAR fFg BAR h BAR i >>
是的,通过使用${var// / ... }
,你可以用任何你想要的东西,包括更多的空格,来替换1个空格。
3. 使用printf
将数组转换为字符串
正如我们所见,使用$IFS
仅限于一个字符。如果你需要使用更多的字符来插入你的字段之间。你必须使用printf
:
ids=("a b" "c d" e\ f)
sep=" long separator "
printf -v string "%s$sep" "${ids[@]}"
echo "${string%$sep}"
a b long separator c d long separator e f
注意:这个语法是可行的,但有一些限制,请继续阅读!
3.1 使用printf
将数组转换为字符串,并传入函数
为了支持特殊字符%
或*
在separator
中的使用,函数必须进行以下处理:
- 防止
%
被printf
解释(printf '%%'
将显示一个%
)
- 防止
*
被参数扩展解释,因此$sep
必须使用双引号引起来。
printArry() {
local sep=$1 string
shift
printf -v string "%s${sep//%/%%}" "$@"
echo "${string%"$sep"}"
}
printArry ' long separator ' "${ids[@]}"
a b long separator c d long separator e f
printArry '*' "${ids[@]}"
a b*c d*e f
printArry '%' "${ids[@]}"
a b%c d%e f
或者在原地合并数组。
mergeArry() {
local sep=$1 string
local -n _array_to_merge=$2
printf -v string "%s${sep//%/%%}" "${_array_to_merge[@]}"
_array_to_merge=("${string%"$sep"}")
}
mergeArry ' another separator ' ids
declare -p ids
declare -a ids=([0]="a b another separator c d another separator e f")
ids=("a b" "c d" e\ f)
mergeArry '*' ids
declare -p ids
declare -a ids=([0]="a b*c d*e f")
4. 使用bash
的参数扩展将数组合并为字符串
又一种方法TMTOWTDI:但是在工作时,我们必须清空$IFS
,我更喜欢在一个函数中使用它来本地化$IFS
。
printArry () {
local -n _array_to_print=$2
local IFS=
local _string_to_print="${_array_to_print[*]/#/"$1"}"
echo "${_string_to_print/#"$1"}"
}
请注意,你可以将
#
替换为
%
。
- "${_array_to_merge[*]/#/$1}"将会将字符串的开头替换为
$1
,而
- "${_array_to_merge[*]/%/$1}"将会将字符串的结尾替换为
$1
,然后
- "${_array_to_merge/#"$1"}"将会将位于字符串开头的$1替换为空,或者
- "${_array_to_merge/%"$1"}"将会将位于字符串结尾的$1替换为空。
mergeArry () {
local -n _array_to_merge=$2
local IFS=
_array_to_merge=("${_array_to_merge[*]/#/"$1"}")
_array_to_merge=("${_array_to_merge/#"$1"}")
}
4.1 根据分隔符的长度进行微小变化:
printArry () {
local -n _array_to_print=$2
local IFS=
local _string_to_print="${_array_to_print[*]/#/"$1"}"
echo "${_string_to_print:${#1}}"
}
mergeArry () {
local -n _array_to_merge=$2
local IFS=
_array_to_merge=("${_array_to_merge[*]/#/"$1"}")
_array_to_merge=("${_array_to_merge:${#1}}")
}
或者
printArry () {
local -n _array_to_print=$2
local IFS=
local _string_to_print="${_array_to_print[*]/%/"$1"}"
echo "${_string_to_print::-${#1}}"
}
5. 比较
待完成...
${${ids[*]}// /|}
是语法错误,仅此而已。不知道你在这里尝试实现什么。 - Gilles Quénotpaste
。 - x-yuri