glob(グロブ)について

  • 33
    Like
  • 3
    Comment
More than 1 year has passed since last update.

皆さんUNIX系OSを使ったことがある方なら、UNIX系OSで以下の様にワイルドカードパターンを使用した経験があると思います。

$ ls -l /tmp/test/*
-rw-r--r--  1 ingktds  wheel  0  2 22 03:27 /tmp/test/aaa
-rw-r--r--  1 ingktds  wheel  0  2 22 03:27 /tmp/test/bbb
-rw-r--r--  1 ingktds  wheel  0  2 22 03:27 /tmp/test/ccc

この様なワイルドカードパターンをglob(グロブ)と言うようです。私もPerlを勉強して初めて知った用語です。

glob

glob, globfree - パターンにマッチするパス名を見付ける。glob() によっ て確保されたメモリ領域を解放する。

例えばこの/tmp/test/*というパスを記述した設定ファイル(test.conf)を読み込むperlスクリプト(test.pl)とbashスクリプト(test.sh)の違いを比較してみましょう。

test.confは/tmp/test/*のパスが書かれているだけのシンプルなファイルです。

test.conf
/tmp/test/*

test.plは単純にtest.confを一気に読み取って配列@lineに代入してその内容をprintしているだけです。

test.pl
#!/usr/bin/env perl
use 5.010000;
use strict;
use warnings;

my $conf = 'test.conf';
open my $fh, '<', $conf;
my @line = <$fh>;
print @line;
close $fh;

その実行結果はまぁそうだよねって感じです。

test.plの実行結果1
$ perl test.pl
/tmp/test/*

test.shも同じでtest.confの内容を一気に読み取って配列LINEに代入してechoしているだけです。

test.sh
#!/bin/bash
CONF=test.conf
LINE=(`cat $CONF`)
echo ${LINE[*]}

その実行結果はおやっ??

test.shの実行結果1
$ bash test.sh
/tmp/test/aaa /tmp/test/bbb /tmp/test/ccc

どうやらbashがglobの機能を如何なく発揮して(アスタリスク)を変数展開してしまったようです。
じゃあどのようしてperlスクリプトと同じように
(アスタリスク)を文字列として認識させるかというと、皆さんまず始めに思いつくのがtest.confの*(アスタリスク)をエスケープすることだと思います。

test.conf
/tmp/test/\*

test.pl,test.shともに同じ実行結果になりましたが、期待している文字列と違う…

test.plの実行結果2
$ perl test.pl
/tmp/test/\*
test.shの実行結果2
$ bash test.sh
/tmp/test/\*

test.confのglobをいちいちエスケープするのも面倒くさいし、そもそも期待している動作と違う。やっぱりtest.confはそのままでやりたい。

test.conf
/tmp/test/*

google先生に聞いてみたらなんとこんなところに同じような悩みにぶち当たっている人が…どうもありがとう!!
globで. ..を除いたドットファイルを得る

こんなときはGLOBIGNOREシェル変数に*を代入してしまえば、globの変数展開は無視されます。使い終わったら必ずunsetしてあげましょう。じゃないと以降の動作にも影響が出てしまいます。

修正版test.sh
#!/bin/bash
CONF=test.conf
GLOBIGNORE=*
LINE=(`cat $CONF`)
echo ${LINE[*]}
unset GLOBIGNORE
test.plの実行結果3
$ perl test.pl
/tmp/test/*
test.shの実行結果3
$ bash test.sh
/tmp/test/*

やっとできたー。