パスワードを忘れた? アカウント作成
936176 journal
Perl

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です。

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • 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
    $

    • by Anonymous Coward

      > $str=;
      ここは$str=<FILE>;と書こうとしたのでしょうか。
      それはともかく、Windows XP上のStrawberry Perlでもosakanataroさんと同じ結果になりました。testとfileがあって"test file"がないときは何も表示されない(-f $fileで正しくファイルなしと判定される)し、testとfileがなくて"test file"があるときはtest_fileが2行表示される(-f $fileで正しくファイルありと判定される)ことも確認しました。
      どんな腐った環境だと「二つのファイルがあるかどうか検査しようとする」のか、どうやってそのことを確認したのかむしろこっちが質問したいですね。

  • by nemui4 (20313) on 2011年12月01日 11時31分 (#2059148) 日記

    空白のあるファイル名が作れるのって知らなかったけどやったら出来てた。
    で、うちでやってるファイルチェックの場合だと大丈夫でした。

    "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.

    大丈夫みたいです。

  • 皆様、ありがとうごさいました。
    -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。

    • すでに自力で答を得ているかもしれませんが御参考までに。

      $filename = "file space";
      open (MD5,"md5sum $filename |");

      のような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を計算しようとして、

      #!/usr/bin/perl --
      # 注: 危険なスクリプト
      foreach my $filename (&lt;*&gt;) {
          open(MD5, "md5sum $filename |");
          print &lt;MD5&gt;;
          close(MD5);
      }

      なんてスクリプトを使ってしまうと、例えばカレントディレクトリに、

      $ touch "&lt;'file space'|rm -rf *"

      なんてやって変な名前のファイルを仕込まれていた場合に泣きます。 良い子は真似しないでね。

      話を戻すと、そもそもPerlが/bin/sh経由でmd5sumを呼び出すのが悪いので、 もっと安全にパイプコマンドを作れば良いのです。 では、どうするか? 悩んだらマニュアルを読みましょう。RTFM!! この場合はopenで悩んでいるので、

      $ perlfunc -f open

      とかやって読みます。するとパイプの説明で盛んに「perlipcを読め」と書いてあるので、そっちも読みます。

      $ man perlipc

      すると"Safe Pipe Opens"節に、 shellに邪魔されない方法が色々書いてあります。好きなやり方を選びましょう。TMTOWTDI.

      Ubuntu 11.10ならこんな感じで動くはず。

      open(MD5, "-|", "md5sum", $filename)

      ちなみにsystemとかbacktick(qx//または``)とかも同様の問題を孕んでおり、 解決策も似ているので以下RTFM。

      では引き続きPerlプログラミングをお楽しみ下さい。enjoy!

      親コメント
    • by Anonymous Coward

      そこでファイル名をクォートしなければいけないのは当たり前だろ。md5sumに限らずコマンドライン引数にファイル名を指定するほとんどどんなプログラムでもまったく同じ話なのに「問題だったのはmd5sum」って…。自分ではない何かのせいにしないと気がすまないの? md5sumは超能力で意図を検知して動作しろとでも?

  • by Anonymous Coward on 2011年12月01日 11時08分 (#2059125)

    perl 変数 空白 展開 でググればヒントが見つかるかも。

typodupeerror

犯人は巨人ファンでA型で眼鏡をかけている -- あるハッカー

読み込み中...