web-dev-qa-db-ja.com

Windowsのコマンドラインで "cd .."が機能するのはなぜですか?

cdcd..の間にスペースを入れずに..と入力すると、Windowsのコマンドプロンプトで親フォルダに切り替わります。この動作についての説明はありますか?コマンドがcommand<space>argumentsの標準フォーマットに従っていません

Working but shouldn't?

また、なぜこれが一貫した結果を生み出さないのでしょうか。

echo..

86
Jonas Köritz

他の回答/コメントの一部に記載されているように、コマンドの後にスペースが必要だという考えは正しくありません。よく知られた例は、最初にスペースを必要とせずに、コマンドの後にスラッシュを入力できることです。

しかし、もう少し理解されていない別の動作があり、あなたが尋ねている「cd..」を許可します。この動作により、「cd\」が機能するようにもなります。

説明する動作は、コマンドラインインタープリター内部のすべてのコマンドで一貫しています。ピリオド、スラッシュ、バックスラッシュなどの特定の記号がある場合、前の文字が「コマンドラインインタープリター」シェル(CMD.EXEまたはその先行コマンドCOMMAND.COMの内部にあるコマンドであるかどうかを確認するためにチェックされます。 )。

これは、Wordがファイルまたはサブディレクトリを参照しているかどうかを確認する前に行うことができます。 cdコマンドについても同様です。悲劇的なことに、サンプルを作成するときに、これはcopyコマンドでは発生しないため、結果には一貫性がないことがわかりました。すべての内部コマンドで必ずしも同じとは限りません。他のコマンド行deldirも(多くの)比較するために検索を続けなかったので、スペースなしで何が起こるかに依存しようとする場合は、非常に注意することをお勧めします。

さて、質問はechoコマンドについても尋ねました:これは珍しい例外です。echo.はDOSの専門家によく知られていると思います。これはおそらく文書化されました。少なくともWin7のCMDでの動作は、コマンドが "echo."で始まる場合、最初のピリオドは無視されます。したがって、「echo..hi」は「.hi」の出力になります。これは、「echo.」を使用して空行を印刷できるようにするためです。対照的に、Unixでは、「echo」コマンドを単独で実行するだけでこれを実行できます。ただし、DOSでは、「echo」コマンドを単独で実行すると、現在の「echo」設定が出力されます。同様に、DOSは "Echo *Off*"および "Echo *On*"を現在のエコー設定を変更する特別な値として扱います。実際にWord "Off"を印刷したい場合は、 "Echo.Off"でトリックを行います(少なくともMicrosoftの最近のバージョンでは- CMDコマンドラインインタープリター。)

そのため、少なくともechoコマンドには半合理的な説明があります。残りのコマンドについては、内部コマンドが優先されると考えていました。しかし、いくつかのテストを行おうとしたときに、実際にはかなり矛盾していることがわかりました。ここで文書化したいくつかの例を使用して、これを示します。


下記は用例です。昇格したコマンドプロンプトを使用したので、UACがルートディレクトリへの書き込みについて不満を抱かないようにしました。これは、Microsoft Windows 7のCMD.EXEで行われました。古いMS-DOSバージョンのCOMMAND.COM、または他社がリリースしたソフトウェア(DR-DOSのCOMMAND.COM)など、他のバージョンでは動作が異なる可能性があります。

(この答えはすでにかなり長いので、ファイルシステムで行った混乱をすべてクリーンアップするコマンドは含めていません。クリーンアップは少しありますが、それほど多くはありません。)

内部コマンドが優先順位を作成することを証明する例はここにあります。 (二重コロンを使用してコメントとして効果的に機能するあまり知られていない機能も示します。これはバッチファイルでもうまく機能します。技術的には、バッチファイルでは、GOTOが到達できないラベルとして処理され、終了しますREMコマンドよりも高速です。)

C:\ something> md cd
C:\ something> echoecho subdir>> cd\a.bat
C:\ something> md\a
C:\ something> 。\ cd\a.bat
subdir

C:\ something> ::サブディレクトリから実行された
C:\ something> cd\a
C:\ a> ::現在のディレクトリが変更されたため、cdが優先されました
更新:さらに実験すると、内部のcdコマンドは、指定されたディレクトリにピリオドが含まれていない場合にのみファイルシステムよりも優先されることがわかりました。したがって、「a.bat」という名前のディレクトリがある場合、「**cd\a.bat**」を実行するとバッチファイルが実行されます。

(ほとんどのディレクトリにはピリオドが含まれていない可能性が高いため)あまり一般的ではない動作を調査した結果、調査結果が更新されました。 cdコマンドは、実際にcopyコマンドに、私が最初に思ったよりも似た振る舞いをしていることがわかりました。

最初はcdcopyのコマンドは異なる動作をすると考えていましたが、今では、提供している名前のパターンが原因であることがわかりました。それでも、以前の結果を確認し、以前に文書化されたテストが名前にピリオドと拡張子が含まれる場合と含まれない場合の違いを示すのに役立つと判断しました。そのため、私はまだ古い調査結果を以下に含めています(ほとんど変更されていませんが、いくつかの非常にマイナーな更新があるので、私の言うことは正確です)。

完全なパスでcopyを使用する例を示します。拡張子を使用しない場合はcdと同じ優先順位(内部コマンドを優先)を使用しません。

C:\ something> エコーエコールート>>\try.bat
C:\ something> md copy
C:\ something> エコーエコーサブディレクトリ>> copy\try.bat
C:\ something> 。\ copy\try.batはサブディレクトリから実行されます
サブディレクトリ

C:\ something> copy\try.bat
サブディレクトリ

C:\ something> ::えっ?なぜそれをオーバーライドしてルートから実行しなかったのですか?
C:\ something> ::どうやら、内部copyコマンドは、サブディレクトリと完全なファイル名(偶数ただし、ディレクトリに拡張子がない場合、内部cdコマンドが優先されました)
C:\ something> ::
C:\ something> ::別のテスト:最後に無駄な期間を追加できます
C:\ something> 。\ copy ..\try.bat
サブディレクトリ

C:\ something> ::わかりました。しかし、これはサブディレクトリをチェックしません:
C:\ something> copy ..\try.bat
1個のファイルがコピーされました。

C:\ something> ::内部コピーコマンドを実行したこと

私の初期の発見は、これらの結果がコマンドラインシェルが優先権を与えることを示していることを示していました。

  • 内部コマンドの名前の直後にバックスラッシュを指定する場合、(内部copyコマンドの代わりに)ファイルシステムに
  • 内部コマンドの名前の直後にバックスラッシュを指定する場合、内部cdコマンド(ファイルシステムの代わりに).
  • 内部コマンドの名前の直後にピリオドを指定する場合、内部copyコマンド(ファイルシステムの代わりに).

これは、動作がcopyコマンド(拡張子を含む完全なファイル名)とcdコマンド(ディレクトリ名の一部として拡張子なし)。バックスラッシュを使用する場合、copyコマンド(完全なファイル拡張子を使用)は最初にファイルシステムをチェックしますが、cdコマンドは実行しません(ディレクトリに拡張子が含まれていない場合)。

(更新:最初は、不整合はプログラム間の異なる動作に基づいていると考えました。後で、不整合が存在することを発見しましたが、提供されたパラメータからより多くの原因でした。)

実際、これらの箇条書きでさえも、私が言った個々のことをすべて実証しているように見えたとしても、完全に正確ではありません。問題は、箇条書きのリストが完全に正確になるほど正確ではないということです。 (これらの箇条書きを比較的簡単に比較し、比較的簡単にチェックできるように、不正確なものを残しました。)

ただし、より正確にするために、最初の箇条書きでは、コマンドラインシェルが優先されることを指摘する必要があります。

  • バックスラッシュを指定するとき、内部のcopyコマンドの代わりにファイルシステムに、andのフルパスの残り、内部コマンドの名前の直後

以下は、私がその区別をしている理由を示しています。

C:\ elsewhere> echoこの行に必要なUACの標高>>\needext
C:\ elsewhere> echoこの行に必要なUACの標高>>\needext.bat
C:\ elsewhere> md。\ copy
C:\ elsewhere> echo@ Echo subdir>> copy\needext.bat
C:\ elsewhere> 。\ copy\needext
subdir

C:\ elsewhere> copy\needext.bat
subdir

C:\ elsewhere> copy\needext
1個のファイルがコピーされました。

C:\ elsewhere> ::次の行にもUACが必要
C:\ elsewhere> del\needext
C:\ elsewhere> del\needext.bat

(最後のcopyコマンドは、内部のcopyコマンドが使用されたため、\ needextと呼ばれるファイルを検索したことに注意してください。ファイル\needext.batは、Wordcopyを含むコマンドラインで使用されなかったことを簡単に示すためにのみ作成されました。

この時点で、バックスラッシュを使用すると、(copyコマンドの動作と)矛盾が発生します...

次に、これらのコマンド間に一貫性があることを示します。 (つまり、一貫性があります...ええと...一貫性がない場合があります。)次に示すのは、cdコマンドは、ピリオドが使用されている場合、copyコマンドのように動作します。 copyコマンドは内部コマンドを使用し、cdコマンドも使用します。

C:\ something> md。\ yetmore

C:\ something> cd。\ yetmore

C:\ something\yetmore> md。\ md
C:\ something\yetmore> echoecho subdir>> md\test.bat
C:\ something\yetmore> 。\ md。\ test
subdir

C:\ something\yetmore> md。\ test

C:\ something\yetmore> md。\ test
サブディレクトリまたはファイル。\ testはすでに存在します。

C:\ something\yetmore> ::このエラーは、内部コマンドを実行したことを示しています。
C:\ something\yetmore> md ..\test
C:\ something\yetmore> md。\ cd
C:\ something\yetmore> copy。\ md cd
。\ md\test.bat
1個のファイルがコピーされました。

C:\ something\yetmore> 。\ cd。\ test
subdir

C:\ something\yetmore> cd。\ test
C:\ something\yetmore\test> ::内部コマンドは1つのピリオドで動作しました
C:\ something\yetmore\test> cd ..
C:\ something\yetmore> 。\ cd ..\test
subdir

C:\ something\yetmore> cd ..\test
C:\ something\test> :: 2つのピリオドが使用されている場合、内部コマンドも優先されます

そのため、最初のテストセッションでは、主にcdおよびcopyコマンド(mdおよびdel)、ファイルシステムに実際に優先順位をつけたのは、copyコマンドを使用したときだけで、その後はファイルシステムのみが優先順位を取りました。フルパスを使用する場合。

その後のレビューの後、拡張機能を使用するときにcdコマンドもファイルシステムの優先順位を与えることがわかりました。少なくともこれは、内部コマンドが互いに少し一貫して扱われていることを意味します。ただし、ファイルシステムオブジェクト(ファイルまたはディレクトリ)の名前に基づいて異なる動作を取得することも意味します。これは、ビヘイビアーがいくつかの本当に不明瞭な内部ロジックを使用しているようです。したがって、さまざまなオペレーティングシステムで動作するこの動作を期待することは、おそらくunsafeであると考えるでしょう。

106
TOOGAM

具体的には、コマンド名とその引数はスペースで区切る必要があるとしますが、これは正しくありません。呼び出しが明確に解釈できる限り、呼び出しは有効です。

この場合、最初の引数は.で始まり、.をコマンド名の一部にすることはできないため、cd..は単純に2つの別々のトークンとして解析されます。

通常、あなたの最初の引数はアルファベット文字(例えばパスの始め)で始まるでしょう、それでそれはあなたのコマンド名の中に "にじみ"エラーを起こすでしょう…しかしそれは構文の問題ではありません。それは意味論的なものです。

echoを含む他のコマンドでも同じ効果があります。

echo...
..

この場合、 echoコマンド自体には特別な規則 があるため、ピリオドは2つしかありません。そのため、次のようになります。

echo .

あるいは、これを拡張すると、

echo.

空行のみを出力します。それは便利です。どうやらそれは議論の先頭の期間を無視することによって実装されています。

こんにちは、これはDOS/Batchです。あなたは正気が欲しい? :D

cd..コマンドは正しく、元のコマンドインタプリタcommand.comでそのように定義されていました。これは後でcmd.exeと命名されました。

cd...と同じように特殊文字なので、コマンドインタープリタは\の処理方法を知っています。

19
Overmind

それは後方互換性のハックです。

コマンドラインインタプリタは、CP/Mコマンドインタプリタと下位互換性があるように設計された、元のMSDOSコマンドインタプリタからのコマンドと下位互換性があるように設計されています。 CP/MもMSDOSも、ファイル名に.を許可しませんでした(ファイル名の2つの部分、基本名と拡張子の間の区切り文字として解釈されました)。これは、(少なくともDOSの初期のバージョンでは)コマンドインタプリタが '。'に達した場合にそれを識別できることを意味していました。 (あるいはファイル名に不正な他の文字は)コマンド名の末尾を通過し、コマンド引数に入っていました。これはDOSとCP/Mの両方で非常に一般的に使用されていました - 例えば、dir/wは非常に一般的なコマンドであり、dir /wは水平形式でファイルをリストすることを意味します。

今日、 '。ファイル名に含めることができます。これにより、コマンドの解析方法が複雑になりますが、Shellはまだ正確なファイル名の一部ではない.を引数の始まりとして識別します。これは、何百万ものユーザーがcd..をタイプすることに慣れてきたか、それを含むバッチファイルを多数持っているか、echo.または他の同様のコマンドをたくさん持っているために、主に必要です。

11
Jules