web-dev-qa-db-ja.com

Bash配列を区切り文字列に変換する

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

  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 コマンドで使用される区切り文字列。

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

括弧はstring:ではなくarrayを区切るために使用されるため

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

いくつかのサンプル:$idsに2つの文字列を追加: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[@]}"

arrayidsをスペースでマージした文字列ビルドをstring型の新しい変数に転送します。

注:"${ids[@]}"space-separated文字列を与えると、"${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で遊ぶ:

set | grep ^IFS=
IFS=$' \t\n'
declare -p IFS
declare -- IFS=" 
"
printf "%q\n" "$IFS"
$' \t\n'

文字通り、spacetabulation、および(意味or)line-feed。したがって、最初の文字はスペースです。 *を使用すると、@と同じことが行われます。

しかし

{
    # 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

注:IFS=: read -a array < <(...)は、:を永続的に設定せずに、$IFSをセパレータとして使用します。これは、出力行#2がスペースを区切り文字として提示するためです。

30
F. Hauri

あなたの最初の質問は F。ハウリの答え で既に述べられています。配列の要素を結合する標準的な方法は次のとおりです。

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

evalは悪であると大声で叫ぶ人もいますが、ここでは一重引用符のおかげで完全に安全です。これには利点があります。サブシェルはありません。IFSはグローバルに変更されず、末尾の改行は削除されず、非常に簡単です。

12
gniourf_gniourf

外部コマンドやIFSを操作する必要なく、printfも使用できます。

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 '|'
4
codeforester

引数配列を区切り文字列で分割するユーティリティ関数:

# Split arguments on delimiter
# @Params
# $1: The delimiter string
# $@: The arguments to delimit
# @Output
# >&1: The arguments separated by the delimiter string
split() {
  (($#<2)) && return 1 # At least 2 arguments required
  local -- delim="$1" str
  shift
  printf -v str "%s$delim" "$@"
  echo "${str:0:-${#delim}}"
}

my_array=( 'Paris' 'Berlin' 'London' 'Brussel' 'Madrid' 'Oslo' )

split ', ' "${my_array[@]}"

出力:

Paris, Berlin, London, Brussel, Madrid, Oslo
0
Léa Gris