rcmdnk's blog

アルゴリズムを学ぼう (アスキー書籍)

シェルスクリプトでの配列のソートについて。

sort

Bashなどの配列そのものにはソート機能が無いので、 外部コマンドを使って一度書き出してソートして書き直し、的な事をします。

通常LinuxやMacなんかだとsortコマンドがあるのでこれを使います。

sortは行のソートになるので、書き出しを1行ずつにしてあげて それをまた入れなおす事が必要です。

空白などがある場合を考えると、一行毎に、ということを行うこともあるので、 IFSを改行にしておけば簡単に出来ます。

sort.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env bash
arr1=("bbb" "aaa" "ccc" "a b")
echo "arr1"
echo "${arr1[@]}"
echo
orig_ifs=$IFS
IFS=$'\n'
arr2=($(echo "${arr1[*]}" | sort))
IFS=$orig_ifs
echo "arr2"
echo "${arr2[@]}"
echo
for v in "${arr2[@]}";do echo $v;done

こんな感じでarray2の右辺の様にソートしてあげれば 1

$ ./sort.sh
arr1
bbb aaa ccc a b

arr2
a b aaa bbb ccc

a b
aaa
bbb
ccc

と、空白がある場合でも正しくソートされます。

もし、空白がないことが確実な場合ははもっと簡単に

arr2=($(for v in "${arr1[@]}"; do echo "$v"; done|sort))
$ arr1=(100 22 324 -1 3 0 -30)
$ arr2=($(for v in "${arr1[@]}"; do echo "$v"; done|sort -n))
$ for i in ${arr2[@]};do echo $i;done

数字のソートをしたいときは、sortの数字をソートする-nオプションを使って

arr2=($(for v in "${arr1[@]}"; do echo "$v"; done|sort -n))

とすればOK。

$ arr1=(100 22 324 -1 3 0 -30)
$ arr2=($(for v in "${arr1[@]}"; do echo "$v"; done|sort -n))
$ for i in ${arr2[@]};do echo $i;done
$ arr1=(100 22 324 -1 3 0 -30)
$ arr2=($(for v in "${arr1[@]}"; do echo "$v"; done|sort -n))
$ for i in ${arr2[@]};do echo $i;done
-30
-1
0
3
22
100
324
$
Sponsored Links
  1. ここではIFSが改行なので"${arr[*]}"*を使った場合に ""で囲うと、全項目がIFSで繋げられた一つの文字列、 と解釈されるので1行に1項目の出力になります。

    一方、"${arr[@]}"としてしまうと、それぞれの項目が1つずつ順番に 区別して表示されるのですが、この時、それぞれの間にはIFSの値によらず 表示上はスペースが挿入されます。

    "で囲わない場合は@でも*でも単にスペースが各項目に挿入された形で 表示されます。

    なので、上の様な形で配列の要素を1行毎に表示させたい場合には *かつ全体を"で囲う、ということが必要になります。

Sponsored Links

« シェルスクリプトでの$@の罠 Moshを使ってみる »

}