スクリプトに渡す引数でワイルドカードが展開され、困る


Q:ワイルドカードを展開しないまま、スクリプトに渡すことはできるか?
A:未解決。シングルクオートでくくってもうまくいかない(cygwin, Linux)。


要件:
スクリプトのなかでfindを使いたい。
このとき、-name オプションで、ファイルパターンを指定したい。
このとき、ファイルパターンにワイルドカードを使いたい。


予想:
ワイルドカードつかっててもシングルクオートでくくっていれば、
展開されないままコマンド(やスクリプト)に渡るのだとばかり思っていた。
つまり、コマンド(やスクリプト)にワイルドカード
文字列として渡したい場合はシングルクオートでくくれば
よいのだと思っていた。


実際:
\*.javaにマッチするファイルがあるディレクトリで
スクリプトを実行すると、スクリプトの引数で'*.java'としても、
$変数値としては展開後の値が入っている。詳しくは下の記録を。
そのため、値が期待どおりにはfindコマンドに渡らず、
findからエラーが返る。


結果を要約すると:
マッチするファイルがあるディレクトリで実行。シングルクオートあり。→ 失敗
マッチするファイルがあるディレクトリで実行。シングルクオートなし。→ 失敗
マッチするファイルがないディレクトリで実行。→ うまくいく


とりあえず:
ワイルドカードが展開されて困るのは、スクリプト実行ディレクトリに
パターンにマッチするファイルがある場合のみ。とりあえず今は、
ひとつ上位のディレクトリで *.java を含まないディレクトリから
実行してしのぐ。しのぎますが、気持ち悪い。


ついでに、同じように、*.javaでヒットする階層で find . -name '*.java'
を実行しても、ちゃんとうまくいく。→ find には、
ワイルドカードが展開されずに渡っているということ。


Linuxは↓で試した。

[test]$ bash -version
GNU bash, version 2.05b.0(1)-release (i386-redhat-linux-gnu)
Copyright (C) 2002 Free Software Foundation, Inc.

cygwinは↓で試した。

/usr/bin bash$bash -version
GNU bash, version 2.05b.0(1)-release (i686-pc-cygwin)
Copyright (C) 2002 Free Software Foundation, Inc.


cygwinで試した時の記録

findsh.sh

#!/bin/sh

echo find + grep result:
find $1 -name $2 | xargs grep -n $3
echo '$1 =' $1
echo '$2 =' $2
echo '$3 =' $3


↑のスクリプトに'*.java'という文字列を渡したい。



マッチするファイルがあるディレクトリで実行。シングルクオートあり。→ 失敗

~/tmp/find_test bash$ls -l
total 3
-rwxr-xr-x    1 Administ なし            7 Feb 16 17:04 abc.java*
-rwxr-xr-x    1 Administ なし            7 Feb 16 17:04 abc.java~*
-rw-r--r--    1 Administ なし            0 Feb 16 14:09 abc.txt
-rwxr-xr-x    1 Administ なし           15 Feb 16 17:04 xyz.java*
-rw-r--r--    1 Administ なし            0 Feb 16 12:15 xyz.java~
-rw-r--r--    1 Administ なし            0 Feb 16 12:15 xyz.txt

~/tmp/find_test bash$~/scripts/findsh.sh . '*.java' final
find + grep result:
find: paths must precede expression ← findの怒り
Usage: find [path...] [expression]
$1 = .
$2 = abc.java xyz.java ← 該当ファイルが展開されて変数に入っている
$3 = final
~/tmp/find_test bash$


マッチするファイルがあるディレクトリで実行。シングルクオートなし。→ 失敗

~/tmp/find_test bash$ls -l
total 3
-rwxr-xr-x    1 Administ なし            7 Feb 16 17:04 abc.java*
-rwxr-xr-x    1 Administ なし            7 Feb 16 17:04 abc.java~*
-rw-r--r--    1 Administ なし            0 Feb 16 14:09 abc.txt
-rwxr-xr-x    1 Administ なし           15 Feb 16 17:04 xyz.java*
-rw-r--r--    1 Administ なし            0 Feb 16 12:15 xyz.java~
-rw-r--r--    1 Administ なし            0 Feb 16 12:15 xyz.txt
~/tmp/find_test bash$~/scripts/findsh.sh . *.java final
find + grep result: ← 該当なしという結果
$1 = .
$2 = abc.java ← 展開・ソートされた1番目が入っている
$3 = xyz.java← 展開・ソートされた2番目が入っている

マッチするファイルがないディレクトリで実行。→ うまくいく

~/tmp/find_test bash$cd ..
~/tmp bash$ls -l
total 0
drwxr-xr-x+   2 Administ なし            0 Feb 16 09:53 cat_test/
drwxr-xr-x+   2 Administ なし         4096 Feb 16 17:04 find_test/
drwxr-xr-x+   3 Administ なし         4096 Feb 16 12:09 rgrep_test/
~/tmp bash$~/scripts/findsh.sh . '*.java' final
find + grep result:
./find_test/abc.java:1:final
./find_test/xyz.java:5:final
$1 = .
$2 = *.java
$3 = final

Linuxで試した時の記録 結果はcygwinの時と同じ。

スクリプト

#!/bin/sh

echo find + grep result:
find $1 -name $2 | xargs grep -n $3
echo '$1 =' $1
echo '$2 =' $2
echo '$3 =' $3

マッチするファイルがあるディレクトリで実行。シングルクオートあり。→ 失敗

[soot@soot-linux find_test]$ ls -l
合計 8
-rw-rw-r--    1 soot   soot          6  2月 16 16:34 abc.java
-rw-rw-r--    1 soot   soot          0  2月 16 15:26 abc.txt
-rw-rw-r--    1 soot   soot          7  2月 16 16:34 xyz.java
-rw-rw-r--    1 soot   soot          0  2月 16 15:26 xyz.txt
[soot@soot-linux find_test]$ ~/scripts/findsh.sh . '*.java' final
find + grep result:
find: paths must precede expression ← find の怒り
Usage: find [path...] [expression]
$1 = .
$2 = abc.java xyz.java ← ワイルドカード展開+ソート
$3 = final
[soot@soot-linux find_test]$

マッチするファイルがあるディレクトリで実行。シングルクオートなし。→ 失敗

[soot@soot-linux find_test]$ ls -l
合計 8
-rw-rw-r--    1 soot   soot          6  2月 16 16:34 abc.java
-rw-rw-r--    1 soot   soot          0  2月 16 15:26 abc.txt
-rw-rw-r--    1 soot   soot          7  2月 16 16:34 xyz.java
-rw-rw-r--    1 soot   soot          0  2月 16 15:26 xyz.txt
[soot@soot-linux find_test]$ ~/scripts/findsh.sh . *.java final
find + grep result: ← 期待とは違うように実行され、該当なし
$1 = .
$2 = abc.java ← ワイルドカード展開
$3 = xyz.java ← ワイルドカード展開
[soot@soot-linux find_test]$


マッチするファイルがないディレクトリで実行。→ うまくいく

[soot@soot-linux find_test]$ cd ..
[soot@soot-linux test]$ ls -l
合計 4
drwxrwxr-x    2 soot   soot       4096  2月 16 16:34 find_test
[soot@soot-linux test]$ ~/scripts/findsh.sh . '*.java' final
find + grep result:
./find_test/abc.java:1:final
./find_test/xyz.java:2:final
$1 = .
$2 = *.java
$3 = final
[soot@soot-linux test]$