join数组的元素?
如果我在Bash中有这样一个数组:
FOO=( abc )
我如何用逗号join元素? 例如,生产a,b,c
。
Pascal Pilz重写解决scheme作为100%纯Bash(无外部命令)的function:
function join_by { local IFS="$1"; shift; echo "$*"; }
例如,
join_by , a "bc" d #a,bc,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 , abc #a,b,c join_by ' , ' abc #a , b , c join_by ')|(' abc #a)|(b)|(c join_by ' %s ' abc #a %sb %sc join_by $'\n' abc #a<newline>b<newline>c join_by - abc #abc join_by '\' abc #a\b\c
又一个解决scheme:
#!/bin/bash foo=('foo bar' 'foo baz' 'bar baz') bar=$(printf ",%s" "${foo[@]}") bar=${bar:1} echo $bar
编辑:相同,但多字符可变长度分隔符:
#!/bin/bash separator=")|(" # eg 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
$ foo=(a "bc" d) $ bar=$(IFS=, ; echo "${foo[*]}") $ echo "$bar" a,bc,d
也许,例如,
SAVE_IFS="$IFS" IFS="," FOOJOIN="${FOO[*]}" IFS="$SAVE_IFS" echo "$FOOJOIN"
这是一个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 $
这甚至保留了换行符,并且不需要一个子shell来获得函数的结果。 如果你不喜欢printf -v
(为什么你不喜欢它?)并传递一个variables名,你当然可以使用一个全局variables作为返回的string:
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}" }
令人惊讶的是,我的解决scheme还没有给:)这是我最简单的方法。 它不需要一个function:
IFS=, eval 'JOINED="${FOO[*]}"'
重复使用@并不重要“的解决scheme,而是通过避免$ {1}的replace和一个中间variables的需要来进行一个声明。
echo $(printf "%s," "${LIST[@]}" | cut -d "," -f 1-${#LIST[@]} )
printf的'格式string被重复使用,以满足参数的需要。 在其手册页中,以便将string的连接logging下来。 然后诀窍是使用LIST长度来切割最后一个分析器,因为当字段计数时,cut仅保留LIST的长度。
s=$(IFS=, eval 'echo "${FOO[*]}"')
接受任何长度的分隔符的printf解决scheme(基于@无关紧要)
#/!bin/bash foo=('foo bar' 'foo baz' 'bar baz') sep=',' # can be of any length bar=$(printf "${sep}%s" "${foo[@]}") bar=${bar:${#sep}} echo $bar
我会将数组作为string回显,然后将空格转换为换行符,然后使用paste
将所有内容join到一行中,如下所示:
tr " " "\n" <<< "$FOO" | paste -sd , -
结果:
a,b,c
这对我来说似乎是最快最干净的!
$ set a 'bc' d $ history -p "$@" | paste -sd, a,bc,d
最佳答案的较短版本:
joinStrings() { local a=("${@:3}"); printf "%s" "$2${a[@]/#/$1}"; }
用法:
joinStrings "$myDelimiter" "${myArray[@]}"
现在我正在使用:
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 ' ' ','`"
哪些工作,但(在一般情况下),如果arrays元素有一个空间,将打破可怕的。
(对于那些感兴趣的,这是一个围绕pep8.py的包装脚本)
$ FOO=( abc ) $ BAR=${FOO[@]} $ BAZ=${BAR// /,} $ echo $BAZ a,b,c
警告,它假定元素没有空格。
perl用于多字符分隔符:
function join { perl -e '$s = shift @ARGV; print join($s, @ARGV);' "$@"; } join ', ' abc # a, b, c
或者在一行中:
perl -le 'print join(shift, @ARGV);' ', ' 1 2 3 1, 2, 3
这种方法处理值中的空格,但需要一个循环:
#!/bin/bash FOO=( abc ) BAR="" for index in ${!FOO[*]} do BAR="$BAR,${FOO[$index]}" done echo ${BAR:1}
如果你想要join的元素不是一个只是空格分隔string的数组,你可以这样做:
foo =“aa bb cc dd”bar = for i in $foo; do printf ",'%s'" $i; done
for i in $foo; do printf ",'%s'" $i; done
for i in $foo; do printf ",'%s'" $i; done
bar = $ {bar:1} echo $ bar'aa','bb','cc','dd'
例如,我的用例是一些string在我的shell脚本中传递,我需要使用它在SQL查询上运行:
./my_script“aa bb cc dd”
在my_script中,我需要执行“SELECT * FROM table WHERE name IN('aa','bb','cc','dd'),那么上面的命令将会很有用。
我的企图
$ array=(one two "three four" five) $ echo "${array[0]}$(printf " SEP %s" "${array[@]:1}")" one SEP two SEP three four SEP five
如果你在一个循环中构build数组,这里有一个简单的方法:
arr=() for x in $(some_cmd); do arr+=($x,) done arr[-1]=${arr[-1]%,} echo ${arr[*]}
也许我错过了一些明显的东西,因为我是整个bash / zsh的新手,但是在我看来,你根本不需要使用printf
。 如果没有,也不会变得非常难看。
join() { separator=$1 arr=$* arr=${arr:2} # throw away separator and following space arr=${arr// /$separator} }
至less,它迄今为止一直在为我工作,没有问题。
例如, join \| *.sh
join \| *.sh
,让我们说我在我的~
目录,输出utilities.sh|play.sh|foobar.sh
。 对我来说足够了。
编辑:这基本上是无Geisweiller的答案 ,但泛化为一个函数。
liststr="" for item in list do liststr=$item,$liststr done LEN=`expr length $liststr` LEN=`expr $LEN - 1` liststr=${liststr:0:$LEN}
最后还要照顾额外的逗号。 我不是bash的专家。 只是我的2C,因为这是更基本和可以理解的
awk -v sep=. 'BEGIN{ORS=OFS="";for(i=1;i<ARGC;i++){print ARGV[i],ARGC-i-1?sep:""}}' "${arr[@]}"
要么
$ a=(1 "ab" 3) $ b=$(IFS=, ; echo "${a[*]}") $ echo $b 1,ab,3