4

Windows の git bash で次の git コマンドを使用しています。

git log --format="%C(cyan)%cd%Creset %s" --date=short -5

コミット日 ( %cd) の後にコミット メッセージ ( %s) が表示されます。コミット日は、カラー マーカーで囲まれています:%C(cyan)カラー出力を開始し、カラー出力%Cresetを停止します。

cmdgit bash では問題なく動作します%cd%が、Windows シェルによって現在の作業ディレクトリ ( $PWDbash と同等)に展開されるとうまくいきません。

したがって、そのコマンドを 経由cmdで実行すると、最初の列にコミット日付の代わりに現在の作業ディレクトリが表示されます! ギットバッシュ:

2015-10-08 commit msg
2015-10-08 commit msg
2015-10-07 commit msg
2015-10-06 commit msg
2015-10-06 commit msg

コマンド:

D:\git\someFolderCreset commit msg
D:\git\someFolderCreset commit msg
D:\git\someFolderCreset commit msg
D:\git\someFolderCreset commit msg
D:\git\someFolderCreset commit msg

実際、私はcmd自分で直接使用したことはありません.nodejs(0.12)スクリプトを書いているときにこの動作を見つけました。

require('child_process').execSync('git log --format=...', {stdio: 'inherit'})

これは、Windows では when を使用してノードによって実行されますcmd)。

簡単な回避策は、スペースを導入し%cd%て見つからないようにすることです。つまり、

git log --format="%C(cyan)%cd%Creset %s" --date=short -5

git log --format="%C(cyan)%cd %Creset%s" --date=short -5

ただし、これにより冗長なスペースが導入されました(以前に別のスペースを削除しまし%sたが、それはまだハックであり、手動の介入が必要です)。

Windows シェルによる拡張を防ぐ方法はありますか?

の使用またはエスケープに関する情報を見つけましたが、ここでは解決策ではありません。%%^%%

# produces superfluous ^ characters
git log --format="%C(cyan)^%cd^%Creset %s" --date=short -5

^2015-10-08^ commit msg
^2015-10-08^ commit msg
^2015-10-07^ commit msg
^2015-10-06^ commit msg
^2015-10-06^ commit msg

# seems the expansion is done at command parse time
git log --format="%C(cyan)%%cd%%Creset %s" --date=short -5

%D:\git\someFolder commit msg
%D:\git\someFolder commit msg
%D:\git\someFolder commit msg
%D:\git\someFolder commit msg
%D:\git\someFolder commit msg

理想的な解決策は、冗長な文字を生成せずに bash および cmd と互換性があるか、Windows 用の一般的な UNIX-y コマンドをエスケープして拡張を防止する JavaScript のエスケープ関数 (そのようなエスケープ関数を作成できる場合) のいずれかです。

4

2 に答える 2

7

MC NDの役立つ回答に代わるものを提供するには:

本当にシェルを関与させる必要があるcmd.exe 場合 (コマンドを WindowsとBashの両方で動作させたいと述べているため、その可能性は低いです)、すぐ下の解決策を検討してください。問題を回避するシェルのない代替手段については、下部の解決策を参照してください。

インスタンス間の潜在的な変数名ではなく、インスタンスの周りに二重引用符を配置することを提案することによって私の元のアプローチを改善し、明確化を提案するためのMC NDへの帽子のヒントre 。% %execFileSync


「エスケープ」%文字。為にcmd.exe

MC ND's answerに記載されているように、Windows コマンド プロンプトで技術的にエスケープすることはできません%(バッチ ファイル内では使用できますが%%、Node.js などの他の環境からシェル コマンドを呼び出す場合は機能せず、通常は機能しません。プラットフォーム)。

ただし、回避策は、各インスタンスを二重引用符で囲むこと%です。

// Input shell command.
var shellCmd = 'git log --format="%C(cyan)%cd%Creset %s" --date=short -5'

// Place a double-quote on either end of each '%'
// This yields (not pretty, but it works):
//   git log --format=""%"C(cyan)"%"cd"%"Creset "%"s" --date=short -5
var escapedShellCmd = shellCmd.replace(/%/g, '"%"')

// Should work on both Windows and Unix-like platforms:
console.log(require('child_process').execSync(escapedShellCmd).toString())

挿入された二重引用符により、変数参照cmd.exeなどのトークンが認識されなくなります (展開されません)。 %cd%"%"cd"%"

ターゲット プログラムによって処理されるときに、余分な二重引用符が最終的に文字列から取り除かれるため、これは機能します。

  • Windows : git.exe(おそらく C ランタイムを介して) 結合された文字列から余分な二重引用符を取り除きます。

  • Unix ライク(Bash などの POSIX ライクなシェル): シェル自体が二重引用符をターゲット プログラムに渡す前に削除します。

    • 警告:一般に、コマンドで二重引用符$を使用するということは、POSIX のようなシェルがプレフィックス付きのトークンで望ましくない可能性のある拡張を実行することに注意する必要があることを意味します(ここでは問題ではありません)。ただし、Windows との互換性を維持するには、二重引用符を使用する必要があります。

技術的には、この手法を二重引用符で囲まれた文字列に適用すると、引用符で囲まれていないインスタンスが散在する一連の二重引用符で囲まれた部分文字列に分割されます。POSIX ライクなシェルは、これを単一の文字列として認識します。部分文字列は二重引用符で囲まれ、インスタンスに直接隣接します。(この手法を引用符のない文字列に適用すると、論理が逆になります。つまり、二重引用符で囲まれたインスタンスを効果的にスプライシングしていることになります。) 文字列の一部ではなく構文上の要素と見なされる部分文字列を囲む二重引用符は、次のようになります。部分文字列が結合されて単一のリテラルが形成され、ターゲット プログラムに渡されるときに削除されます。 %%%


シェルを完全に回避して問題を回避する

:次のビルドは、外部実行可能ファイルを呼び出すexecFile[Sync]場合にのみ機能します(OPの場合に当てはまります:)-対照的に、シェルビルトイン(内部コマンド)またはWindowsバッチファイルを呼び出す場合、回避できないため、(onウィンドウズ)。[1]git.exeexec[Sync]cmd.exe

ではなくを使用するexecFileSyncexecSyncと、シェル ( cmd.exeWindows の場合) は関与しないため、文字のエスケープについて心配する必要はありません。%またはその他のシェルのメタ文字、さらに言えば:

require('child_process').execFileSync('git', 
   [ 'log', 
     '--format=%C(cyan)%cd%Creset %s',
     '--date=short',
     '-5' ], {stdio: 'inherit'})

引数は、配列の要素として個別に指定する必要があり、引用符を埋め込まないことに注意してください


[1] Windows では、スクリプト ファイル (Python スクリプトなど) を で直接呼び出すことはできませんが、実行するファイルとしてexecFile[Sync]インタプリタ実行可能ファイル (たとえばpython) を渡し、スクリプト ファイルを引数として渡すことができます。Unix ライクなプラットフォームでは、スクリプトにシバン行があり、実行可能としてマークされている限り、スクリプトを直接呼び出すことができます。を使用して Windowsバッチ ファイルを呼び出すことができますが、.
execFile[Sync] cmd.exeexec[Sync]

于 2015-10-08T21:35:53.243 に答える
4

要するに、あなたはそれを行うことができないか、少なくとも一般的な方法はありません

私が間違っていたことに注意してください。mklement0 の回答は、一般的な解決策への道を示しています。

もちろん、 , を使用^してパーセント記号をエスケープするのではなく (コマンド ライン レベルでパーセント記号をエスケープすることはできません)、展開される変数として検出されないように変数の名前からパーセント記号を分離することができます。つまり、あなたの場合、使用するのに十分です

git log --format="%C(cyan)%cd^%Creset %s" --date=short -5

ただし、指摘したように、キャレットはパーサーによって消費されず、出力文字列に含まれます。

そのため、「エスケープ」文字は と の両方の出力に含まれますがcmdbashこの特定の (または同様の) ケースについては、次を使用して解決できます。

process.env.cd = '%cd%'
require('child_process').execSync(
    'git log --format="%C(cyan)%cd%Creset %s" --date=short -5'
    , {stdio: 'inherit'}
)

基本的に、コードが行うことは、環境変数に偽の値を割り当てcdてリテラルに変更することです%cd%。そのため、cmdパーサーが変数展開を実行すると、正しい値がコマンド ラインで終了します。

gitしかし、おそらく(コードがどのように/何をするかをチェックしていません)cd変数を変更すると干渉する可能性があります。したがって、この場合も、cd変数の値を変更する代わりに、使用できる

process.env['C(cyan)'] = '%C(cyan)%';

なんで?パーサーがコマンド ラインを処理するとき、cmdフォーマット文字列の先頭を既存の変数と照合し、展開を行い、同じプロセスで%cd%変数の開始パーセント記号を消費するため、展開されません。

于 2015-10-08T18:21:11.937 に答える