1. ホーム
  2. arrays

[解決済み] Bashで配列をソートする方法

2022-03-06 07:51:12

質問

Bashで配列を持っているのですが、例えば。

array=(a c b f 3 5)

配列をソートする必要があります。単に内容をソートして表示するだけでなく、ソートされた要素で新しい配列を取得する必要があります。ソートされた新しい配列は、まったく新しいものであっても、古いものであってもかまいません。

どのように解決するのですか?

それほど多くのコードは必要ありません。

IFS=$'\n' sorted=($(sort <<<"${array[*]}"))
unset IFS

要素内の空白をサポートする(改行でない限り)。 はBash 3.xで動作します。

などです。

$ array=("a c" b f "3 5")
$ IFS=$'\n' sorted=($(sort <<<"${array[*]}")); unset IFS
$ printf "[%s]\n" "${sorted[@]}"
[3 5]
[a c]
[b]
[f]

は、@sorontar が 指摘 のようなワイルドカードを含む要素は、注意が必要である。 * または ? :

sorted=($(...))の部分は、"split and glob"演算子を使っています。globをオフにしたほうがいいです。 set -f または set -o noglob または shopt -op noglob のような配列の要素、あるいは * は、ファイルのリストに展開されます。

何が起きているのか

この順番で起こる6つのことの集大成が、この結果なのです。

  1. IFS=$'\n'
  2. "${array[*]}"
  3. <<<
  4. sort
  5. sorted=($(...))
  6. unset IFS

まず IFS=$'\n'

これは、次のように2と5の結果に影響を与える重要な操作部分です。

与えられた。

  • "${array[*]}" の最初の文字で区切られたすべての要素に展開されます。 IFS
  • sorted=() のすべての文字で分割し、要素を作成します。 IFS

IFS=$'\n' 設定する を使用して要素が展開されるようにします。 改行 を区切り文字とし、後で各行が1つの要素になるように作成します。 (つまり、改行で分割する)。

改行で区切ることが重要なのは、そうやって sort が動作します(行単位でのソート)。 で分割する。 のみ は、それほど重要ではありませんが、スペースやタブを含む要素を保持するために必要です。

のデフォルト値は IFS スペース , タブ が続きます。 改行 となり、運用に適さない。

次に sort <<<"${array[*]}" 部分

<<< という ここの文字列 の展開を取る。 "${array[*]}" の標準入力に送り込みます。 sort .

この例では sort には、次のような文字列が入力されます。

a c
b
f
3 5

以降 sort ソート を生成します。

3 5
a c
b
f

次に sorted=($(...)) 部分

$(...) という部分は コマンド置換 の場合、そのコンテンツ ( sort <<<"${array[*]} ) は通常のコマンドとして実行され、その結果生じる 標準出力 をリテラルとして使用し、そのリテラルは $(...) があった。

この例では、単に書くのと同じようなものができあがります。

sorted=(3 5
a c
b
f
)

sorted は、このリテラルを改行ごとに分割して作成される配列になります。

最後に unset IFS

の値をリセットします。 IFS をデフォルト値に設定することは、単なるグッドプラクティスです。

に依存しているものとの間でトラブルを起こさないようにするためです。 IFS は、スクリプトの後半で使用します。 (そうでなければ、複雑なスクリプトでは実用的でないような、物事の切り替えを覚えておく必要があります)。