パスワードを忘れた? アカウント作成
2853459 journal
日記

jordan_bethの日記: del コマンドの腐った仕様 16

日記 by jordan_beth

とあるバッチスクリプトをコーディング中なのだが、その終了処理で、使用したテンポラリファイルを削除する次の一文があったんだ。

del /f /s /q "%FILENAMEVAR%" > NUL 2>&1

「これならバッチファイル実行中に確認プロンプトやらエラーやら表示しないぜ」なんて得意になってたわけだ。で、ある程度出来上がって実行していると、カレントディレクトリのファイルが消えていく…。運の悪いことにテスト実行はスクリプトがおいてあるディレクトリ。いくつかスクリプトを仕上げていたんだが、これが全部なくなっていた…

なんとか削除ファイル復活ソフトを使って一つだけスクリプトを救出、調べてみたら、上の del 文が問題だった。ヘルプ出力時にはメインコードをすっ飛ばして(%FILENAMEVAR%を設定せずに)終了処理を行なっていた。

del /f /s /q "" > NUL 2>&1

が実行されていたわけだ(しかも確認プロンプト、エラーメッセージなしで)。それでも、それはコーディング中想定していた。「空文字指定でも大丈夫だしぃぃい~~」

しかし、マイクロソフトの実装は俺の予想を遙かに超える、超異次元的なものだった。コマンドプロンプトで空文字指定の del コマンドを実行してみる。

C:\Documents and Settings\foo>del ""
C:\Documents and Settings\foo\*、よろしいですか (Y/N)?

( ゚д゚)
(つд⊂)ゴシゴシ
( ゚д゚)
Σ(゚д゚lll)ガーン

工工エエエエエ(´Д`)エエエエエ工工

マイクロソフト的解釈によると、空文字ファイル=ワイルドカード、となってしまうのかぁぁぁぁ
ふざけるなァァ俺の3日間を返せーーーー
(まー XP は10年前のOSだしなー と思って 7 でやっても同じだった .....)

よくある(あった) rm -rf / のトラップに引っかかってしまった気分だ。しかもトラップに引っかかってしまった相手は信頼すべきマイクロソフトという巨大企業。

ということで、こんな夜更け、というか夜明けに(しかも GW なのに)スラドで日記を書いて、憂さ晴らしをしてみる。
#できりゃ Python でやりたかったけど、どうしても Pure DOSバッチじゃないといかん案件だったんだよな(TдT)

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • C:\temp\work>del "
    C:\temp\work\*、よろしいですか (Y/N)?

    del コマンドは、ダブルクォーテーション1キャラクタでもって、
    アスタリスク相当のワイルドカードとして扱っているように見えます。

    ひょっとして、シェルが悪者か? と思い、
    他のコマンドでも試してみましたが、del コマンド以外では、
    同様の動作は確認できませんでした。

    // win xp sp2

  • by Anonymous Coward on 2012年04月30日 6時29分 (#2144990)

    IF EXIST "%FILENAMEVAR%" del /f /s /q "%FILENAMEVAR%" > NUL 2>&1
    みたいにすればだいじょうぶなのでは?

    • いやまぁ、原因がわかってればそうなんですが、今までの経験上(bash, perl, pythonなど)、空文字指定でファイルが削除されるなんて思ってもいなかったわけで。

      ヘルプ処理でメインコードが実行されていなくても、delさんは華麗にスルーしてくれる、と信じて疑わなかったわけです。だからこそ強制削除&出力廃棄していたんで....

      --
      ん? 俺、今何か言った?
      親コメント
      • by Ryo.F (3896) on 2012年04月30日 10時30分 (#2145027) 日記

        まあ、なんて言うか、いまどきcmd.exeでもなかろうよ。PowerShellを使うべき場面だろうね。条件が許さなければ仕方ないけど。

        親コメント
        • by Anonymous Coward

          まあ、なんて言うか、いまどきcmd.exeでもなかろうよ。PowerShellを使うべき場面だろうね。条件が許さなければ仕方ないけど。

          おまえはなにを言っているんだ?
          Remove-Itemに空文字食わせたって、エラーで死ぬだけじゃねーか?

          そもそも他の処理系と同じようにスルーしてりゃ問題ないのに
          勝手に変な解釈して、いつもいつも大きなお世話をしてくれるMSの処理系が問題の根本なんだよ
          CMDからPowerShellに代えようがそれは何ひとつ変わらない

          # MSの処理系はAPIひとつに至るまで未定義の動作が多すぎる
          # しかも「未定義=デフォルト」じゃないから、ある日突然MSがデフォルトの動作を決めて
          # それまで「未定義=デフォルト」だと仮定していた全てに問題が起きる
          # C/C++のようにそれが未定義ならちゃんと、「 ~な時の動作は未定義である」と書いておいてくれなきゃ困るわ >>>>>MS

          • by Ryo.F (3896) on 2012年04月30日 17時33分 (#2145129) 日記

            Remove-Itemに空文字食わせたって、エラーで死ぬだけじゃねーか?

            それでいいじゃない。少なくとも、今回のような悲劇は無かっただろ?

            そもそも他の処理系と同じようにスルーしてりゃ問題ないのに

            それは思想の差。すべての処理系が同じ思想で設計される必要は無い。君の思想だけが正しいわけでもない。

            CMDからPowerShellに代えようがそれは何ひとつ変わらない

            それはウソ。少なくとも今回のような場合の結果は違うんだから。

            いまどきCMD.exeもVBScriptもJScriptも使おうとは思わないけど、PowerShellはそう悪くないよ。配列指向を理解するのに時間はかかるかも知れないけど。
            例えば、今回のようなケースであれば、次を参考にコーディングすればいいよ。

            $ $file = 'a.txt'
            $ '' | Set-Content $file
            $ dir
             
                ディレクトリ: C:\TMP
             
            Mode                LastWriteTime     Length Name
            ----                -------------     ------ ----
            -a---        2012/04/30     16:44          2 a.txt
             
            $ @() | Remove-Item
            $ dir
             
                ディレクトリ: C:\TMP
             
            Mode                LastWriteTime     Length Name
            ----                -------------     ------ ----
            -a---        2012/04/30     16:44          2 a.txt
             
            $ @($file) | Remove-Item
            $ dir
            $

            これなら、空列を渡してもエラーにはならない。まあ、空文字列を渡しちゃうとエラーになるけどね。

            要するに、これが思想の差。他の処理系とは違うけど、悪かぁないだろ? こういう処理系があってもいいんじゃない? いろんなものがあった方が、世の中楽しいだろ?

            あ、もちろんPowerShellにもエラー処理構文は準備されているから、それを使ってもいいと思うよ。

            親コメント
          • by Ryo.F (3896) on 2012年04月30日 17時48分 (#2145136) 日記

            こう言う方法もあるよ。

            $ Remove-Item ''
            Remove-Item : 引数が空の文字列であるため、パラメーター 'Path' にバインドできません。
            <<略>>
            $ $ErrorActionPreference = 'SilentlyContinue'
            $ Remove-Item ''
            $

            しかし、こんな風にはできない。

            $ Remove-Item '' -ErrorAction SilentlyContinue
            Remove-Item : 引数が空の文字列であるため、パラメーター 'Path' にバインドできません。
            <<略>>
            $

            まあ、これが良い設計か、って言うと疑問だけどね。

            親コメント
        • by Anonymous Coward

          まあ、なんて言うか、いまどきcmd.exeでもなかろうよ。PowerShellを使うべき場面だろうね。条件が許さなければ仕方ないけど。

          他人に提供するものだと素のOS標準で使えるものっていう条件がついたりするんですよね。
          自分でしか使わないなら、間違いなくbashで組むけど。

          • by Ryo.F (3896) on 2012年04月30日 22時27分 (#2145237) 日記

            他人に提供するものだと素のOS標準で使えるものっていう条件がついたりするんですよね。

            そうだね。元の話はXPだから、標準搭載ではないね。
            でも、Windows 7・Windows Server 2008(無印)以降には標準搭載だよ。

            自分でしか使わないなら、間違いなくbashで組むけど。

            Bashは悪くない。Ryo.F自身、手元のマシンにはCygwinを入れている。
            だけど、.Netとかにはアクセスできないだろ? 今後のことも考えれば、PowerShellの方がいいと思うよ。

            親コメント
      • by Anonymous Coward
        sh 系のスクリプトでは事前に変数に値が設定されているかチェックするのが常道だと思うのですけども、後の祭り。
  • by shesee (27226) on 2012年04月30日 18時50分 (#2145155) 日記
    使用中のファイルのmvが出来るようになって欲しいな
  • by Anonymous Coward on 2012年04月30日 7時00分 (#2144991)

    >運の悪いことにテスト実行はスクリプトがおいてあるディレクトリ。いくつかスクリプトを仕上げていたんだが、これが全部なくなっていた…
    こ、こわいなー。怪談にはまだ時期が早いですよ。

    ホームディレクトリでこれやったら泣ける。
    つーか、死ねる。

    >コマンドプロンプトで空文字指定の del コマンドを実行してみる。
    ひょっとして、Windows的には「空文字」と「引数無し」(或いはnull)の区別がないのか?

    で、
    del "" → del
    に変換されて、デフォルト処理が「全削除」とか?
    #「いや、その理屈はおかしい」。やっぱりMSの考えることは理解不能だ。

typodupeerror

192.168.0.1は、私が使っている IPアドレスですので勝手に使わないでください --- ある通りすがり

読み込み中...