string 将 Bash 数组转换为分隔字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13470413/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 01:43:29  来源:igfitidea点击:

Converting a Bash array into a delimited string

arraysstringbashdelimited-text

提问by koola

I would like to know the following;

我想知道以下内容;

  1. Why the given non-working example doesn't work.
  2. If there are any other cleaner methods than those given in working example.
  1. 为什么给定的非工作示例不起作用。
  2. 如果有任何其他比工作示例中给出的更清洁的方法。

Non-working example

非工作示例

> ids=(1 2 3 4);echo ${ids[*]// /|}
1 2 3 4
> ids=(1 2 3 4);echo ${${ids[*]}// /|}
-bash: ${${ids[*]}// /|}: bad substitution
> ids=(1 2 3 4);echo ${"${ids[*]}"// /|}
-bash: ${"${ids[*]}"// /|}: bad substitution

Working example

工作示例

> ids=(1 2 3 4);id="${ids[@]}";echo ${id// /|}
1|2|3|4
> ids=(1 2 3 4); lst=$( IFS='|'; echo "${ids[*]}" ); echo $lst
1|2|3|4

In context, the delimited string to be used in a sedcommand for further parsing.

在上下文中,要在sed命令中用于进一步解析的分隔字符串。

采纳答案by F. Hauri

# REVISION: 2017-03-14
# Use of read and other bash specific features (bashisms)

Because parentheses are used to delimit an array, not a string:

因为括号用于分隔数组,而不是字符串:

ids="1 2 3 4";echo ${ids// /|}
1|2|3|4

Some samples: Populating $idswith two strings: a band c d

一些示例:填充$ids两个字符串: a bc d

ids=("a b" "c d")

echo ${ids[*]// /|}
a|b c|d

IFS='|';echo "${ids[*]}";IFS=$' \t\n'
a b|c d

... and finally:

......最后:

IFS='|';echo "${ids[*]// /|}";IFS=$' \t\n'
a|b|c|d

Where array is assembled, separated by 1st char of $IFS, but with space replaced by |in each element of array.

组装数组的地方,由 的第一个字符分隔$IFS,但|在数组的每个元素中替换为空格。

When you do:

当你这样做时:

id="${ids[@]}"

you transfer the string build from the merging of the arrayidsby a space to a new variable of type string.

您从的合并传送串构建阵列ids通过的空间类型的新变量字符串

Note:when "${ids[@]}"give a space-separatedstring, "${ids[*]}"(with a star *instead of the at sign @) will render a string separated by the first character of $IFS.

注意:"${ids[@]}"给出一个空格分隔的字符串时,"${ids[*]}"(用星号*而不是 at 符号@)将呈现一个由 的$IFS一个字符分隔的字符串。

what man bashsays:

什么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>''.

Playing with $IFS:

$IFS

set | grep ^IFS=
IFS=$' \t\n'
set | grep ^IFS=
IFS=$' \t\n'

declare -p IFS
declare -- IFS=" 
"
printf "%q\n" "$IFS"
$' \t\n'

Literally a space, a tabulationand (meaning or)a line-feed. So, while the first character is a space. the use of *will do the same as @.

字面意思是 a space、 atabulation(意思是或)a line-feed。所以,虽然第一个字符是一个空格。的使用*@.

But:

但是

{

    # OIFS="$IFS"
    # IFS=$': \t\n'
    # unset array 
    # declare -a array=($(echo root:x:0:0:root:/root:/bin/bash))
    # OIFS="$IFS"
    # IFS=$': \t\n'
    # unset array 
    # declare -a array=($(echo root:x:0:0:root:/root:/bin/bash))

    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

Note:The line IFS=: read -a array < <(...)will use :as separator, without setting $IFSpermanently. This is because output line #2present spaces as separators.

注:该生产线IFS=: read -a array < <(...)将使用:作为分隔符,没有设置$IFS永久。这是因为输出行#2存在空格作为分隔符。

回答by gniourf_gniourf

Your first question is already addressed in F. Hauri's answer. Here's canonical way to join the elements of an array:

您的第一个问题已在F. Hauri 的回答中解决。这是连接数组元素的规范方法:

ids=( 1 2 3 4 )
IFS=\| eval 'lst="${ids[*]}"'

Some people will cry out loud that evalis evil, yet it's perfectly safe here, thanks to the single quotes. This only has advantages: there are no subshells, IFSis not globally modified, it will not trim trailing newlines, and it's very simple.

有些人会大声喊叫这eval是邪恶的,但由于单引号,这里非常安全。这只具有优点:没有子shell,IFS没有全局修改,不会修剪尾随的换行符,而且非常简单。

回答by codeforester

You can use printftoo, without any external commands or the need to manipulate IFS:

您也可以使用printf,无需任何外部命令或操作 IFS:

ids=(1 2 3 4)                     # create array
printf -v ids_d '|%s' "${ids[@]}" # yields "|1|2|3|4"
ids_d=${ids_d:1}                  # remove the leading '|'

回答by Léa Gris

An utility function to join arguments array into a delimited string:

将参数数组连接到分隔字符串的实用函数:

#!/usr/bin/env bash

# Join arguments with delimiter
# @Params
# : The delimiter string
# ${@:2}: The arguments to join
# @Output
# >&1: The arguments separated by the delimiter string
array::join() {
  (($#)) || return 1 # At least delimiter required
  local -- delim="" str IFS=
  shift
  str="${*/#/$delim}" # Expand arguments with prefixed delimiter (Empty IFS)
  echo "${str:${#delim}}" # Echo without first delimiter
}

declare -a my_array=( 'Paris' 'Berlin' 'London' 'Brussel' 'Madrid' 'Oslo' )

array::join ', ' "${my_array[@]}"
array::join '*' {1..9} | bc # 1*2*3*4*5*6*7*8*9=362880 Factorial 9

declare -a null_array=()

array::join '== Ultimate separator of nothing ==' "${null_array[@]}"

Output:

输出:

Paris, Berlin, London, Brussel, Madrid, Oslo
362880