「Windowsでエクスプローラーからフォルダを各種ターミナルで開く」の版間の差分
Notion-MW |
Notion-MW |
||
(同じ利用者による、間の5版が非表示) | |||
34行目: | 34行目: | ||
* Git BashではWindowsの実行ファイルにスラッシュ付きオプションを渡すときはスラッシュを2つにする必要がある。<code>cmd //c</code>や<code>bcdedit //v</code>など。 | * Git BashではWindowsの実行ファイルにスラッシュ付きオプションを渡すときはスラッシュを2つにする必要がある。<code>cmd //c</code>や<code>bcdedit //v</code>など。 | ||
* printf関数の%qオプションを使うと、文字列を<strong>エスケープされた状態にして</strong>返してくれる。これはshからの呼び出し先の別のshで再びフォルダ名をcdなどの引数として利用したいときに使える。 | * printf関数の%qオプションを使うと、文字列を<strong>エスケープされた状態にして</strong>返してくれる。これはshからの呼び出し先の別のshで再びフォルダ名をcdなどの引数として利用したいときに使える。 | ||
** | ** bash(POSIX互換ではない)の組み込みコマンドのprintfと、独立実行ファイル(GNU Coreutilsの一部)である/bin/printfがある。基本的な趣旨としては同一のコマンドだが、組み込みコマンドのほうは入力に<code>"</code>が含まれていない限り結果にも<code>"</code>が使われることはないようで、このおかげで意図しない動作を回避できることがある。今回扱う例に関しては前者が後者の上位互換であるということになる。後者を使っているものはそれでも動いたものである。 | ||
** そもそも%qは組み込みコマンドのほうにしかないという話もある。環境によって違いそう。 | ** そもそも%qは組み込みコマンドのほうにしかないという話もある。環境によって違いそう。 | ||
* <code>\\?\</code>が付くような長いパスをカレントディレクトリにしていても、Git Bash/Cygwinに付属の(というかMSYS/Cygwin向けにコンパイルされた?)exeなら実行できる。 | * <code>\\?\</code>が付くような長いパスをカレントディレクトリにしていても、Git Bash/Cygwinに付属の(というかMSYS/Cygwin向けにコンパイルされた?)exeなら実行できる。 | ||
* Git Bashの(ba)shは<code>--login</code> | * Git Bashの(ba)shは<code>--login</code>をつけて起動してもカレントディレクトリが維持されるが、<s>Cygwinの(ba)shは</s><s><code>--login</code></s><s>をつけると強制的にホームディレクトリに移動する。</s> | ||
** 2024/4頃、Cygwinの挙動が変化し、カレントディレクトリが維持されるようになっていることに気付く。変わっていた方のバージョンは3.5.3、変わっていない方は3.3.6であった。 | |||
** ところで、[https://superuser.com/questions/345964/start-bash-shell-cygwin-with-correct-path-without-changing-directory Start bash shell (cygwin) with correct path without changing directory - Super User]の通り、<code>CHERE_INVOKING</code>という変数を1に設定しておけばカレントディレクトリは維持される。 | |||
* Git Bashにおいては環境変数を正しく設定するため<code>--login</code>の時点で環境変数<code>MSYSTEM</code>を<code>MINGW64</code>にしておく必要がある。[[Windowsでのターミナル環境|Windowsでのターミナル環境]] 参照。 | * Git Bashにおいては環境変数を正しく設定するため<code>--login</code>の時点で環境変数<code>MSYSTEM</code>を<code>MINGW64</code>にしておく必要がある。[[Windowsでのターミナル環境|Windowsでのターミナル環境]] 参照。 | ||
49行目: | 51行目: | ||
* powershell.exe | * powershell.exe | ||
** -Commandがなくても付けたのと同じ扱いになる? | ** -Commandがなくても付けたのと同じ扱いになる? | ||
*** 逆に、- | *** 逆に、-Commandを付けなければいけないという点を除いてはpwshがpowershellの上位互換という感覚である(新しいのでそれはそう)。 | ||
** <code>`</code>や<code>[]</code>を含むフォルダの扱いにバグがあり、cmdなどでこれらのフォルダをカレントディレクトリとした状態で5系のPowerShellを起動すると<code>C:\</code>や<code>C:\Windows\System32\WindowsPowerShell\v1.0></code>をカレントディレクトリとして起動される(たとえば<code>C:\somefolder][</code>なら前者、<code>C:\somefolder[]</code>なら後者)。 | ** <code>`</code>や<code>[]</code>を含むフォルダの扱いにバグがあり、cmdなどでこれらのフォルダをカレントディレクトリとした状態で5系のPowerShellを起動すると<code>C:\</code>や<code>C:\Windows\System32\WindowsPowerShell\v1.0></code>をカレントディレクトリとして起動される(たとえば<code>C:\somefolder][</code>なら前者、<code>C:\somefolder[]</code>なら後者)。 | ||
** -Fileを使用してスクリプトを実行するとき、ダブルクォーテーションで囲われていない <code>-</code> が引数に含まれているとエラーになるバグがある。 | ** -Fileを使用してスクリプトを実行するとき、ダブルクォーテーションで囲われていない <code>-</code> が引数に含まれているとエラーになるバグがある。 | ||
73行目: | 75行目: | ||
これを防ぐ方法はいくつかある。ちなみに、<code>%%</code>でのエスケープというのはバッチファイルの中だけの話で、今回の場面では以下より簡単なエスケープ方法は多分ないと思う。 | これを防ぐ方法はいくつかある。ちなみに、<code>%%</code>でのエスケープというのはバッチファイルの中だけの話で、今回の場面では以下より簡単なエスケープ方法は多分ないと思う。 | ||
< | <ol style="list-style-type: decimal;"> | ||
<li><p>既に定義されているかもしれない環境変数をバックアップし、一時的にその中身を<code>%</code>に変えて使用することでリテラル文字としての<code>%</code>を表現し、後で元に戻す。</p> | <li><p>既に定義されているかもしれない環境変数をバックアップし、一時的にその中身を<code>%</code>に変えて使用することでリテラル文字としての<code>%</code>を表現し、後で元に戻す。</p> | ||
<p>すなわち、<code>MY_PERCENT</code>のような変数の中身をバックアップし、<code>MY_PERCENT</code>の中身を<code>%</code>に変え、未知の文字列中の<code>%</code>をすべて<code>%MY_PERCENT%</code>にすることで<strong>この部分が置換によって</strong><strong><code>%</code></strong><strong>に変わるのを利用して</strong><code>%</code>をそのまま渡すということである(環境変数の置換は左から順に行われるため、たとえば<code>%MY_PERCENT%PATH%MY_PERCENT%</code>の<code>%PATH%</code>が置換されることはない)。受け渡しが終わったら<code>MY_PERCENT</code>の中身を復元する。</p> | <p>すなわち、<code>MY_PERCENT</code>のような変数の中身をバックアップし、<code>MY_PERCENT</code>の中身を<code>%</code>に変え、未知の文字列中の<code>%</code>をすべて<code>%MY_PERCENT%</code>にすることで<strong>この部分が置換によって</strong><strong><code>%</code></strong><strong>に変わるのを利用して</strong><code>%</code>をそのまま渡すということである(環境変数の置換は左から順に行われるため、たとえば<code>%MY_PERCENT%PATH%MY_PERCENT%</code>の<code>%PATH%</code>が置換されることはない)。受け渡しが終わったら<code>MY_PERCENT</code>の中身を復元する。</p> | ||
87行目: | 89行目: | ||
<li>[https://learn.microsoft.com/en-us/windows/win32/procthread/environment-variables Environment Variables - Win32 apps | Microsoft Learn]では「<code>=</code>は環境変数に使えない」と書かれていて、ダイアログからでも設定はできないが、レジストリだと無理やり設定できる。 | <li>[https://learn.microsoft.com/en-us/windows/win32/procthread/environment-variables Environment Variables - Win32 apps | Microsoft Learn]では「<code>=</code>は環境変数に使えない」と書かれていて、ダイアログからでも設定はできないが、レジストリだと無理やり設定できる。 | ||
<ul> | <ul> | ||
<li>ユーザー環境変数に設定する分にはとりあえず問題なさそうだが、システム環境変数にレジストリから<code>=</code>(と、<code>=</code>を名前に含むいくつかの変数。どれが原因かは正確にはわからない)を無理やり追加したら<strong>0xc000021のブルースクリーンでWindowsが起動しなくなった</strong> | <li>ユーザー環境変数に設定する分にはとりあえず問題なさそうだが、システム環境変数にレジストリから<code>=</code>(と、<code>=</code>を名前に含むいくつかの変数。どれが原因かは正確にはわからない)を無理やり追加したら<strong>0xc000021のブルースクリーンでWindowsが起動しなくなった</strong>(Linuxからchntpwで該当の変数を全て削除したら治った)のでこれはやってはいけない。</li></ul> | ||
</li> | </li> | ||
<li>ちなみに、<code>=</code>や<code>%</code>はUnix側では特殊文字ではないので、printfとの適用順はあまり気にする必要はない。</li></ul> | <li>ちなみに、<code>=</code>や<code>%</code>はUnix側では特殊文字ではないので、printfとの適用順はあまり気にする必要はない。</li></ul> | ||
96行目: | 98行目: | ||
</li> | </li> | ||
<li>ただ、<code>==%</code>を<code>%</code>に置換するという操作はPowerShellやshにとっては容易でもcmdにとっては不可能に近いので、最終的な呼び出し先がcmdであるときには採用しづらい。</li></ul> | <li>ただ、<code>==%</code>を<code>%</code>に置換するという操作はPowerShellやshにとっては容易でもcmdにとっては不可能に近いので、最終的な呼び出し先がcmdであるときには採用しづらい。</li></ul> | ||
</li></ | </li></ol> | ||
また、今回の記事ではcmdやvbsのRunを経由してコマンドを実行しているものが多くあるが、<strong>このスクリプトの内容自体もエスケープが必要</strong>である。つまり、例えば<code>cmd /c</code>の内側に<code>$mypath.Replace('%','%MY_PERCENT%')</code>というPowershellコードが含まれるなら、<code>','</code>や<code>MY_PERCENT</code>という環境変数が定義されていた時にその部分が置換されてしまう。これを回避するのはそこまで難しくなく、この例であれば<code>$mypath.Replace('%'.Trim('='),'%'.Trim('=')+'MY_PERCENT%')</code>のように<code>=</code>を含む無意味なコードを挿入すればよい。また、<code>%</code>をいったん<code>==%</code>にしている部分に関しては、<code>==%</code>ではなく<code>==%==</code>にすることで問題を避けられるだろう。無駄に複雑になるのでスクリプト例ではそのような措置はしていない。 | また、今回の記事ではcmdやvbsのRunを経由してコマンドを実行しているものが多くあるが、<strong>このスクリプトの内容自体もエスケープが必要</strong>である。つまり、例えば<code>cmd /c</code>の内側に<code>$mypath.Replace('%','%MY_PERCENT%')</code>というPowershellコードが含まれるなら、<code>','</code>や<code>MY_PERCENT</code>という環境変数が定義されていた時にその部分が置換されてしまう。これを回避するのはそこまで難しくなく、この例であれば<code>$mypath.Replace('%'.Trim('='),'%'.Trim('=')+'MY_PERCENT%')</code>のように<code>=</code>を含む無意味なコードを挿入すればよい。また、<code>%</code>をいったん<code>==%</code>にしている部分に関しては、<code>==%</code>ではなく<code>==%==</code>にすることで問題を避けられるだろう。無駄に複雑になるのでスクリプト例ではそのような措置はしていない。 | ||
197行目: | 199行目: | ||
<p>カレントディレクトリをコンソールに出力する。(ちなみにpwdの由来はprint working directoryなのでそれに倣った)</p></li></ul> | <p>カレントディレクトリをコンソールに出力する。(ちなみにpwdの由来はprint working directoryなのでそれに倣った)</p></li></ul> | ||
<span id="注意:- | <span id="注意:-当初は後述のnoworkingdirectoryを知らなかったので1の方法に頼っていたが実際には2の方法のほうが簡明なのでそちらを使うことを勧める1と11は残しておくが読む必要はあまりない"></span> | ||
== 注意: 当初は後述のNoWorkingDirectoryを知らなかったので1.の方法に頼っていたが、実際には2.の方法のほうが簡明なので、そちらを使うことを勧める。1. | == 注意: 当初は後述のNoWorkingDirectoryを知らなかったので1.の方法に頼っていたが、実際には2.の方法のほうが簡明なので、そちらを使うことを勧める。1.(と1.1.)は残しておくが、読む必要はあまりない。 == | ||
{{UnderConstruction|Windowsでエクスプローラーからフォルダを各種ターミナルで開く}} | |||
<span id="1標準入力から受け取る場合"></span> | <span id="1標準入力から受け取る場合"></span> | ||
407行目: | 409行目: | ||
<p><code>sh -c "IFS=;echo $*" -- "%V</code></p> | <p><code>sh -c "IFS=;echo $*" -- "%V</code></p> | ||
<ul> | <ul> | ||
<li>最後が<code>"%V</code>と閉じられていないのはミスではなく、<code>"%V"</code>としてしまうと<code>C:\</code>のときに<code>C:"</code> | <li>最後が<code>"%V</code>と閉じられていないのはミスではなく、<code>"%V"</code>としてしまうと<code>C:\</code>のときに<code>C:"</code>が渡されてしまうのでそれを避けるためである(これはかなりトリッキーなのでもう少し真面目にやってもいいかなとは思う)。</li> | ||
<li>UNCパスの最初の<code>\\</code>が<code>\</code>に変わってしまう(手元では、Cygwinの場合は<code>\\?\</code>のみで発生している?)という問題があり、適宜置換する必要がある。</li></ul> | <li>UNCパスの最初の<code>\\</code>が<code>\</code>に変わってしまう(手元では、Cygwinの場合は<code>\\?\</code>のみで発生している?)という問題があり、適宜置換する必要がある。</li></ul> | ||
</li></ul> | </li></ul> | ||
466行目: | 468行目: | ||
<p><code>"C:\Program Files\Git\git-bash.exe" -c "IFS=;cd $(echo $*|/bin/sed 's/\\\\/\\\\\\\\/'|/bin/cygpath -f -);exec bash" -- "%V</code></p> | <p><code>"C:\Program Files\Git\git-bash.exe" -c "IFS=;cd $(echo $*|/bin/sed 's/\\\\/\\\\\\\\/'|/bin/cygpath -f -);exec bash" -- "%V</code></p> | ||
<ul> | <ul> | ||
<li><p> | <li><p>ちなみに、Git Bashのインストーラにより設定される「Git Bash Here」メニューでは以下のようになっている。</p> | ||
<p><code>"C:\Program Files\Git\git-bash.exe" "--cd=%v."</code></p> | <p><code>"C:\Program Files\Git\git-bash.exe" "--cd=%v."</code></p> | ||
<p>これは、特殊文字にはすべて対応しているが、(NoWorkingDirectoryをつけたとしても)<code>\\?\</code>で始まるパスではうまくいかない。最後の「.」はよくわからないがこれを付けておくと<code>--cd</code>がうまくやってくれるっぽい。</p></li></ul> | <p>これは、特殊文字にはすべて対応しているが、(NoWorkingDirectoryをつけたとしても)<code>\\?\</code>で始まるパスではうまくいかない。最後の「.」はよくわからないがこれを付けておくと<code>--cd</code>がうまくやってくれるっぽい。</p></li></ul> |