![Perl Perl](https://srad.jp/static/topics/perl_64.png)
sumiyakiの日記: [質問] Perlのファイル検査 -f とスペースの入ったファイル名 11
日記 by
sumiyaki
Perlで
if (-f $filename){
}
みたいなことやるとき、$filenameにスペースの入ったファイル名があったときはどうすればよいのでしょうか?
例えば "file space"というファイルがあったとすると、
-f $filenameでは
"file"
"space"
の二つのファイルがあるかどうか検査しようとします。
"file\ space"でもだめでした。
追記
コメントありがとうございました。
すいません。勘違いでした。-f $filenameはスペースがあってもうまく動きました。作っていたスクリプトで
open(MD5,"md5sum $filename |");
のようなことをしていますが、ここでエラーになっていました。
$filenameが"file¥ space"ならばmd5sumはOK。
お騒がせ致しました。
ちなみに、環境はUbuntu 11.10です。
その環境腐ってない? (スコア:1)
CentOS5環境
$ echo "test" > test
$ echo "file" > file
$ echo "test_file" > test\ file
$ cat test\ file
test_file
$ cat test.pl
#!/usr/bin/perl
$filename="test file";
if (-f $filename ){
open(FILE,$filename);
$str=;
print $str;
close(FILE);
}
if (-f "$filename"){
open(FILE,"$filename");
$str=;
print $str;
close(FILE);
}
$ ls -1
file
test
test file
test.pl
$ perl test.pl
test_file
test_file
$
Re: (スコア:0)
> $str=;
ここは$str=<FILE>;と書こうとしたのでしょうか。
それはともかく、Windows XP上のStrawberry Perlでもosakanataroさんと同じ結果になりました。testとfileがあって"test file"がないときは何も表示されない(-f $fileで正しくファイルなしと判定される)し、testとfileがなくて"test file"があるときはtest_fileが2行表示される(-f $fileで正しくファイルありと判定される)ことも確認しました。
どんな腐った環境だと「二つのファイルがあるかどうか検査しようとする」のか、どうやってそのことを確認したのかむしろこっちが質問したいですね。
Re:その環境腐ってない? (スコア:1)
あ・・・そうです、タグ扱いされて消えてましたね
うちのばあい (スコア:1)
空白のあるファイル名が作れるのって知らなかったけどやったら出来てた。
で、うちでやってるファイルチェックの場合だと大丈夫でした。
"ppp qqq"という名前のファイルを作って。
# touch "ppp qqq"
ファイル名をいったん変数に入れといてチェック。
# vi test.pl
--
#!/bin/perl
$file = "ppp qqq";
if(-f $file){
print "$file is exist.\n";
}
--
# chmod +x test.pl
# ./test.pl
ppp qqq is exist.
大丈夫みたいです。
すいません勘違いでした。問題だったのはmd5sumでした (スコア:1)
皆様、ありがとうごさいました。
-fはスペースの入ったファイル名でも問題はありませんでした。
作っていたスクリプトの
open (MD5,"md5sum $filename |")
のところで、$filenameが"file space"では上手く行かなかったのを-fの問題だと勘違いしました。大変お騒がせ致しました。失礼いたしました。
つまり、
"file space"というファイルがあり、
$filenameが "file space"の時、
-f $filenameはtrueになるが、
open (MD5,"md5sum $filename |")
ではエラーになるということでした。
$filenameが"file\ space"ならば md5sumでもOK。
Re:すいません勘違いでした。問題だったのはmd5sumでした (スコア:1)
すでに自力で答を得ているかもしれませんが御参考までに。
のような2引数のopenでパイプを作ると次のように動きます。
1. Perlが変数$filenameを展開。("md5sum file space |")
2. Perlが末尾のパイプ記号を見て、残りを/bin/shに渡す。("md5sum file space")
3. /bin/shが文字列を空白で区切る。("md5sum", "file", "space")
4. /bin/shが"md5sum"を探して引数("md5sum", "file", "space")を渡す。
5. md5sumが引数を見て"file"と"space"のMD5を計算しようとする。
Perlが/bin/sh経由でmd5sumを実行するので、 空白に限らず、/bin/shの特殊文字が意味を持ってしまいます。
例えば、カレントディレクトリの全ファイルのMD5を計算しようとして、
なんてスクリプトを使ってしまうと、例えばカレントディレクトリに、
なんてやって変な名前のファイルを仕込まれていた場合に泣きます。 良い子は真似しないでね。
話を戻すと、そもそもPerlが/bin/sh経由でmd5sumを呼び出すのが悪いので、 もっと安全にパイプコマンドを作れば良いのです。 では、どうするか? 悩んだらマニュアルを読みましょう。RTFM!! この場合はopenで悩んでいるので、
とかやって読みます。するとパイプの説明で盛んに「perlipcを読め」と書いてあるので、そっちも読みます。
すると"Safe Pipe Opens"節に、 shellに邪魔されない方法が色々書いてあります。好きなやり方を選びましょう。TMTOWTDI.
Ubuntu 11.10ならこんな感じで動くはず。
ちなみにsystemとかbacktick(qx//または``)とかも同様の問題を孕んでおり、 解決策も似ているので以下RTFM。
では引き続きPerlプログラミングをお楽しみ下さい。enjoy!
Re:すいません勘違いでした。問題だったのはmd5sumでした (スコア:1)
shellを通さない方法ありがとうございました (スコア:1)
Shellを通さない方法のご紹介ありがとうございました。
先ほどまで、\,(,),[,],$,|,その他をエスケープするようにコードを組み込んでいました。'と'で挟んでもファイル名が'を含むとうまく行きません。そんな変態なファイル名のファイルを作る人はいないと思いますが。
やはり、このようなことが不要な正しい方法があるのですね。やや新しいPerlの機能なのかな。
大変参考になりました。
Re: (スコア:0)
そこでファイル名をクォートしなければいけないのは当たり前だろ。md5sumに限らずコマンドライン引数にファイル名を指定するほとんどどんなプログラムでもまったく同じ話なのに「問題だったのはmd5sum」って…。自分ではない何かのせいにしないと気がすまないの? md5sumは超能力で意図を検知して動作しろとでも?
Re:すいません勘違いでした。問題だったのはmd5sumでした (スコア:1)
まあ、おっしゃるとおりなんですが、実際にスクリプトを作っている時には、md5sumに渡すときはスペースをエスケープしていて、その時、-fでもそのまま上手く行くはずだと思い込んでしまったのが勘違いのもとだったみたいです。失礼しました。
Perlはよく知らないけど (スコア:0)
perl 変数 空白 展開 でググればヒントが見つかるかも。