LoginSignup
3
2

More than 5 years have passed since last update.

濾過 in シェル

Posted at

濾過演算とは

UNIX 文化では, パイプやリダイレクトで連結することで組み合わせ可能な, 入力を加工して出力する (比較的) 小さな機能のプログラムのことを総じて「フィルタ(濾過器)」と呼びます.

が,

ここで, 題材にする演算は上記の意味ではありません.
引数を一つとり, 真偽値を返す演算「述語 (predicate)」と, 「データ列」を与えると, データ列のうち「述語」が真を返す要素のみ取り出したデータ列を返すような演算は, 多くのプログラミング言語において, 組み込みで, または, 基本ライブラリで提供される大変汎用的な演算です.

言語によって filter, select などの名前で提供されています. 本記事では, 便宜的に「濾過演算」と呼びますが, この日本語名称が一般的という訳でもありません.

多くの繰り返し処理は濾過に抽象化されます.

a = <新しい空のデータ列>;
for (i = 0; i < <データ列>.長さ; i++) {
  if (<述語>(<データ列>[i])) {
    a.append(<データ列>[i]);
  }
}
return a;

のような形の演算は

<濾過> <述語> <データ列>

のように抽象化できます.

また, 濾過として抽象化すると, データ列全体を読み込んで処理する必要がなく, 非常に大きなデータ列に対してシーケンシャルに処理が可能であるという利点もあります. (実装によりますが, あくまでこの抽象化において原理的には.)

以下

  • Ruby の select
  • JavaScript の filter
  • Clojure の filter

で例示します.

以下の環境で試験しました.

% irb --version
irb 0.9.6(09/06/30)

% node --version
v0.10.26

% java -jar clojure-1.7.0.jar
Clojure 1.7.0
user=>

数値の濾過

数値列中の偶数のみ抽出します.

Ruby

irb(main):001:0> [3, 1, 4, 1, 5, 9, 2, 6].select{|i| i%2 == 0}
=> [4, 2, 6]

JavaScript

> [3, 1, 4, 1, 5, 9, 2, 6].filter(function(i){return i%2 == 0})
[ 4, 2, 6 ]

Clojure

user=> (filter even? [3 1 4 1 5 9 2 6])
(4 2 6)

文字列の濾過

文字列の列から長さが 3 以上のものを抽出します.

Ruby

irb(main):002:0> ["May", "I", "have", "a", "large", "container", "of", "coffee"].select{|i| 3 <= i.length}
=> ["May", "have", "large", "container", "coffee"]

JavaScript

> ["May", "I", "have", "a", "large", "container", "of", "coffee"].filter(function(i){return 3 <= i.length})
[ 'May',
  'have',
  'large',
  'container',
  'coffee' ]

Clojure

user=> (filter #(<= 3 (count %)) ["May" "I" "have" "a" "large" "container" "of" "coffee"])
("May" "have" "large" "container" "coffee")

シェルで

前置きが長くなりました. 濾過演算を実装する Bourne Shell スクリプトは以下のようになります.

filter.sh
#!/bin/sh

f=$1
while read line
do
  set "$line"
  if `eval $f`
  then
    echo $line
  fi
done
  • 述語は, 第一引数に「引数を一つとり真偽値を返すプログラム」を与えます.
  • データ列は, 改行区切りで標準入力から与えられるものとします.

真偽値を返すプログラムは「Bourne Shell の if にとって」の真偽ですので, 終了ステータス 0 で終了が真, 0 以外は偽とします. if に対して頻繁に行うように, test コマンド(
MAN page of TEST) のハードリンクである [ を使うことで, 多くの場合は目的に適うでしょう.

上記を filter として PATH 環境変数に含まれるディレクトリに保存 (または保存したディレクトリを PATH に追加) し, 実行パーミッションを与えてある (chmod +x filter してある) ものとして, 以下使い方を例示します.

$/bin/sh --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15)
Copyright (C) 2007 Free Software Foundation, Inc.

で試験しました.

数値の濾過

数値列中の偶数のみ抽出します.

$ echo "3 1 4 1 5 9 2 6" | tr ' ' '\n' | filter '[ `expr $1 % 2` -eq 0 ]'
4
2
6

文字列の濾過

文字列の列から長さが 3 以上のものを抽出します.

$ echo "May I have a large container of coffee" | tr ' ' '\n' | filter '[ 3 -le ${#1} ]'
May
have
large
container
coffee

お読みいただきありがとうございました.

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2