48

私は次のことを知りたいです。

  1. 与えられた機能しない例が機能しない理由。
  2. 作業例に示されている方法以外のよりクリーンな方法がある場合。

動作しない例

> 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

実例

> 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

コンテキストでは、さらに解析するためにsedコマンドで使用される区切り文字列。

4

4 に答える 4

52

括弧は文字列ではなく配列を区切るために使用されるため、次のようになります。

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

いくつかのサンプル:$ids2つの文字列を入力: a bおよびc d

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

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

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

... そして最後に:

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

配列がアセンブルされ、の最初の文字で区切られていますが、配列の各要素で$IFSスペースが置き換えられています。|

あなたがするとき:

id="${ids[@]}"

文字列ビルドを、スペースによる配列 のマージから文字列ids型の新しい変数に転送します。

注:スペースで区切られた文字列を"${ids[@]}"指定すると(アットマークの代わりに星を使用)、の最初の文字で区切られた文字列がレンダリングされます。"${ids[*]}"*@$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

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

文字通り、、spaceおよびtabulationまたは)を意味line-feedます。つまり、最初の文字はスペースです。の使用は*と同じようになり@ます。

しかし

{
    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

于 2012-11-20T10:24:05.393 に答える
22

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 '|'
于 2018-03-08T07:13:37.317 に答える
17

あなたの最初の質問は、F。Hauriの回答ですでに取り上げられています。配列の要素を結合する標準的な方法は次のとおりです。

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

一部の人々は悪を大声で叫ぶでしょうeval、それでもここでは一重引用符のおかげで完全に安全です。これには利点があるだけです。サブシェルIFSがなく、グローバルに変更されず、末尾の改行がトリミングされず、非常にシンプルです。

于 2015-10-28T10:57:00.070 に答える
3

引数配列を区切り文字列に結合するユーティリティ関数:

#!/usr/bin/env bash

# Join arguments with delimiter
# @Params
# $1: 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="$1" 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[@]}"

出力:

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

于 2019-08-17T12:12:06.280 に答える