改めて記事を書き直しました。(2024/02/12)
技術検証もきちんと行なっているのと不要なPerlの記述を削除してわかりやすくまとめています。
以下を参照いただければと思います。
https://inasan.tech/glob/
皆さん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, globfree - パターンにマッチするパス名を見付ける。glob() によっ て確保されたメモリ領域を解放する。
例えばこの/tmp/test/*というパスを記述した設定ファイル(test.conf)を読み込むperlスクリプト(test.pl)とbashスクリプト(test.sh)の違いを比較してみましょう。
test.confは/tmp/test/*のパスが書かれているだけのシンプルなファイルです。
/tmp/test/*
test.plは単純にtest.confを一気に読み取って配列@lineに代入してその内容をprintしているだけです。
#!/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;
その実行結果はまぁそうだよねって感じです。
$ perl test.pl
/tmp/test/*
test.shも同じでtest.confの内容を一気に読み取って配列LINEに代入してechoしているだけです。
#!/bin/bash
CONF=test.conf
LINE=(`cat $CONF`)
echo ${LINE[*]}
その実行結果はおやっ??
$ bash test.sh
/tmp/test/aaa /tmp/test/bbb /tmp/test/ccc
どうやらbashがglobの機能を如何なく発揮して*(アスタリスク)を変数展開してしまったようです。
じゃあどのようしてperlスクリプトと同じように*(アスタリスク)を文字列として認識させるかというと、皆さんまず始めに思いつくのがtest.confの*(アスタリスク)をエスケープすることだと思います。
/tmp/test/\*
test.pl,test.shともに同じ実行結果になりましたが、期待している文字列と違う…
$ perl test.pl
/tmp/test/\*
$ bash test.sh
/tmp/test/\*
test.confのglobをいちいちエスケープするのも面倒くさいし、そもそも期待している動作と違う。やっぱりtest.confはそのままでやりたい。
/tmp/test/*
google先生に聞いてみたらなんとこんなところに同じような悩みにぶち当たっている人が…どうもありがとう!!
globで. ..を除いたドットファイルを得る
こんなときはGLOBIGNOREシェル変数に*を代入してしまえば、globの変数展開は無視されます。使い終わったら必ずunsetしてあげましょう。じゃないと以降の動作にも影響が出てしまいます。
#!/bin/bash
CONF=test.conf
GLOBIGNORE=*
LINE=(`cat $CONF`)
echo ${LINE[*]}
unset GLOBIGNORE
$ perl test.pl
/tmp/test/*
$ bash test.sh
/tmp/test/*
やっとできたー。