joinStrings() { local a=("${@:3}"); printf "%s" "$2${a[@]/#/$1}"; }
用法:
joinStrings "$myDelimiter" "${myArray[@]}"
4
我的尝试 .
$ array=(one two "three four" five)
$ echo "${array[0]}$(printf " SEP %s" "${array[@]:1}")"
one SEP two SEP three four SEP five
0
liststr=""
for item in list
do
liststr=$item,$liststr
done
LEN=`expr length $liststr`
LEN=`expr $LEN - 1`
liststr=${liststr:0:$LEN}
这也会在最后处理额外的逗号 . 我不是bash专家 . 只是我的2c,因为这是更基本和可理解的
-2
这是一个完成工作的100%纯Bash功能:
join() {
# $1 is return variable name
# $2 is sep
# $3... are the elements to join
local retname=$1 sep=$2 ret=$3
shift 3 || shift $(($#))
printf -v "$retname" "%s" "$ret${@/#/$sep}"
}
看:
$ a=( one two "three three" four five )
$ join joineda " and " "${a[@]}"
$ echo "$joineda"
one and two and three three and four and five
$ join joinedb randomsep "only one element"
$ echo "$joinedb"
only one element
$ join joinedc randomsep
$ echo "$joinedc"
$ a=( $' stuff with\nnewlines\n' $'and trailing newlines\n\n' )
$ join joineda $'a sep with\nnewlines\n' "${a[@]}"
$ echo "$joineda"
stuff with
newlines
a sep with
newlines
and trailing newlines
$
join() {
# $1 is sep
# $2... are the elements to join
# return is in global variable join_ret
local sep=$1 IFS=
join_ret=$2
shift 2 || shift $(($#))
join_ret+="${*/#/$sep}"
}
8
Pascal Pilz将重写解决方案作为100%纯Bash中的函数(无外部命令):
function join_by { local IFS="$1"; shift; echo "$*"; }
例如,
join_by , a "b c" d #a,b c,d
join_by / var local tmp #var/local/tmp
join_by , "${FOO[@]}" #a,b,c
或者,我们可以使用printf来支持多字符分隔符,使用@gniourf_gniourf的想法
function join_by { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }
例如,
join_by , a b c #a,b,c
join_by ' , ' a b c #a , b , c
join_by ')|(' a b c #a)|(b)|(c
join_by ' %s ' a b c #a %s b %s c
join_by $'\n' a b c #a<newline>b<newline>c
join_by - a b c #a-b-c
join_by '\' a b c #a\b\c
$ join_ws , a b c
a,b,c
$ join_ws '' a b c
abc
$ join_ws $'\n' a b c
a
b
c
$ join_ws ' \/ ' A B C
A \/ B \/ C
1
这种方法处理值中的空格,但需要循环:
#!/bin/bash
FOO=( a b c )
BAR=""
for index in ${!FOO[*]}
do
BAR="$BAR,${FOO[$index]}"
done
echo ${BAR:1}
10
现在我正在使用:
TO_IGNORE=(
E201 # Whitespace after '('
E301 # Expected N blank lines, found M
E303 # Too many blank lines (pep8 gets confused by comments)
)
ARGS="--ignore `echo ${TO_IGNORE[@]} | tr ' ' ','`"
#!/bin/bash
separator=")|(" # e.g. constructing regex, pray it does not contain %s
foo=('foo bar' 'foo baz' 'bar baz')
regex="$( printf "${separator}%s" "${foo[@]}" )"
regex="${regex:${#separator}}" # remove leading separator
echo "${regex}"
# Prints: foo bar)|(foo baz)|(bar baz
1
不使用外部命令:
$ FOO=( a b c ) # initialize the array
$ BAR=${FOO[@]} # create a space delimited string from array
$ BAZ=${BAR// /,} # use parameter expansion to substitute spaces with comma
$ echo $BAZ
a,b,c
26 回答
重用@并不重要的解决方案,但通过避免$ {:1}替换和需要中间变量的一个声明 .
printf has'格式字符串经常被重用,以满足参数 . 在其手册页中,以便记录字符串的连接 . 然后诀窍是使用LIST长度来切断最后一个sperator,因为cut将仅保留LIST的长度作为字段计数 .
顶级答案的缩短版本:
用法:
我的尝试 .
这也会在最后处理额外的逗号 . 我不是bash专家 . 只是我的2c,因为这是更基本和可理解的
这是一个完成工作的100%纯Bash功能:
看:
这甚至保留了尾随换行符,并且不像
printf -v
(你为什么不喜欢它?)并传递变量名,你当然可以为返回的字符串使用全局变量:Pascal Pilz将重写解决方案作为100%纯Bash中的函数(无外部命令):
例如,
或者,我们可以使用printf来支持多字符分隔符,使用@gniourf_gniourf的想法
例如,
使用变量间接直接引用数组也有效 . 也可以使用命名引用,但它们仅在4.3中可用 .
使用这种形式的函数的优点是你可以让分隔符是可选的(默认为默认的第一个字符
IFS
,这是一个空格;如果你愿意,可以使它成为一个空字符串),它避免了两次扩展值(第一个作为参数传递时,第二个作为函数内的"$@"
) .此解决方案也不要求用户在命令替换中调用该函数 - 它会调用子shell,以获取分配给另一个变量的字符串的连接版本 .
至于缺点:你必须小心传递正确的参数名称,传递
__r
会给你__r[@]
. 变量间接的行为也扩展了其他形式的参数也没有明确记录 .这适用于3.1到5.0-alpha . 如上所述,变量间接不仅适用于变量,也适用于其他参数 .
数组和数组元素也是参数(存储值的实体),对数组的引用在技术上也是对参数的引用 . 和特殊参数
@
非常相似,array[@]
也是有效的参考 .改变或选择性扩展形式(如子串扩展)偏离参数本身的参考不再起作用 .
如果要连接的元素不是数组,只是空格分隔的字符串,您可以执行以下操作:
例如,我的用例是我的shell脚本中传递了一些字符串,我需要使用它来运行SQL查询:
在my_script中,我需要做“SELECT * FROM table WHERE name IN('aa','bb','cc','dd') . 然后上面的命令将很有用 .
也许我是整个bash / zsh的新手,但它看起来像你根本不需要使用
printf
. 如果没有它也不会变得非常难看 .至少,它迄今为止对我有用而没有问题 .
例如,
join \| *.sh
,在我的~
目录中让's say I' m输出utilities.sh|play.sh|foobar.sh
. 对我来说足够好了 .编辑:这基本上是Nil Geisweiller's answer,但推广到一个函数 .
如果您在循环中构建数组,这是一个简单的方法:
我会将数组作为字符串回显,然后将空格转换为换行符,然后使用
paste
将所有内容连接到一行中,如下所示:tr " " "\n" <<< "$FOO" | paste -sd , -
结果:
a,b,c
这对我来说似乎是最快最干净的!
使用perl作为多字符分隔符:
或者在一行中:
也许,例如,
令人惊讶的是我的解决方案尚未给出:)这对我来说是最简单的方法 . 它不需要功能:
注意:观察到此解决方案在非POSIX模式下运行良好 . 在POSIX mode中,元素仍然正确连接,但
IFS=,
变为永久性 .到目前为止,将最好的世界与以下想法相结合 .
这个小小的杰作是
100%纯bash(暂时取消设置IFS的参数扩展,没有外部调用,没有printf ...)
紧凑,完整和完美(适用于单字符和多字符限制器,适用于包含空格的限制器,换行符和其他shell特殊字符,使用空分隔符)
高效(没有子shell,没有数组副本)
简单而愚蠢,在某种程度上,美丽和也很有启发性
例子:
这种方法处理值中的空格,但需要循环:
现在我正在使用:
哪个有效,但(在一般情况下)如果数组元素中有空格,则可能会破坏 .
(对于那些感兴趣的人,这是一个围绕pep8.py的包装脚本)
这不是在父shell中修改
IFS
并且都在一行中:导致
又一个解决方案:
编辑:相同但对于多字符可变长度分隔符:
不使用外部命令:
警告,它假定元素没有空格 .
感谢@gniourf_gniourf对我迄今为止最好的世界组合的详细评论 . 很抱歉发布未完全设计和测试的代码 . 这是一个更好的尝试 .
这种美观的概念是
(仍然)100%纯粹的bash(感谢明确指出printf也是内置的 . 我之前没有意识到这一点......)
适用于多字符分隔符
更紧凑,更完整,这一次仔细考虑和长期压力测试与shell脚本等随机子串,包括使用shell特殊字符或控制字符或在分隔符和/或参数和边缘没有字符案件,角落案件和其他几乎没有参数的狡辩 . 这并不能保证不再有bug,但找到一个会有点难度 . 顺便说一句,即使是目前最高投票的答案和相关的东西都受到像这样的事情的影响......
其他例子:
要么
printf解决方案,接受任何长度的分隔符(基于@并不重要)