Powershell: ネイティブオペレーターを呼び出す

作成日 2020年06月30日  ·  189コメント  ·  ソース: PowerShell/PowerShell

問題文

現在、PowerShellでネイティブコマンドラインの切り取りと貼り付けが期待どおりに実行されない場合があります。 これは、ネイティブコマンドに渡されることを意図した引用符の誤った解析、またはPowerShellとして解釈されることを意図していないPowerShell構文の使用が原因である可能性があります。 PowerShellには--%特別な引数があり、ネイティブコマンドで使用すると、残りの引数はネイティブコマンドに渡されるリテラルとして扱われますが、いくつかの問題があります。

  1. 発見できません。ユーザーはこの特別なパラメータについて事前に知っておく必要があります
  2. |&& 、および||が優先されるため、 wsl --% ls | lesswsl lsを実行し、結果をlessパイプします。 lessではなくPowerShellで実行されている$
  3. コマンドラインをカットアンドペーストする場合は、行を編集して--%を先頭に挿入する必要があります
  4. Unixシステムでは、-%の後の引数は、グロブなしで逐語的に渡されます。Unixのネイティブコマンドは、シェルがグロブを実行することを期待します。

提案された技術的実装の詳細

提案は、新しい--% (Call Native)演算子を導入することです。

この演算子の後のテキストコンテンツは、OSの「デフォルトシェル」を呼び出して実行します。 Windowsでは、これはcmd.exeになり、Unixベースのシステムでは/ bin / shになります。 これにより、Unixベースのシステムでのグロブの問題が解決され、Windowsでの%variable%拡張も可能になります。 --%スイッチとは異なり、これは、 |&& 、および||がネイティブコマンドラインの一部として扱われることも意味します。

これは、これら2つが機能的に同じであることを意味します。

wsl --% ls $foo `&`& echo $PWD
--% wsl ls $foo && echo $PWD

ここで、 $foo$PWDは、WSL内のシェルによって評価されます。 最初の例では、PowerShell内ではなくWSL内で実行するには、 &&をエスケープする必要があることに注意してください。

このような実行からの出力をPowerShellにパイプで戻すには、ユーザーは最初に結果を変数に格納する必要があります。

$out = --% ls *.txt
$out | select-string hello

現在の&呼び出し演算子とは異なり、PowerShell構文を使用できないことに注意してください。

--% $commandline

PowerShellによって最初に$commandlineを変数として解決するのではなく、 $commandlineをデフォルトのシェルに渡して未解決の処理を行います。

カットアンドペーストの問題は、 --%を入力した後に貼り付けるだけで解決します。

上記のwslの例は次のようになります。

--% wsl ls | less

ここでの目的は、その行全体をWSLLinuxインスタンス内で実行することです。

発見可能性

スイッチとして--%既に精通しているユーザーは、意味のあるこの新しい演算子の使用に簡単に移行できます。 新規ユーザーの場合、 --%は一意であるため、検索エンジンはPowerShellに簡単に関連していることがわかります。

別の考慮事項

&!&nが印章として提案されましたが、 &!は一部の言語では有効な演算子であり、ドキュメントのWeb検索がより困難であるため、プッシュバックがありました。 &呼び出し演算子に似たビジュアルがユーザーを混乱させるかどうかという懸念もありました。

この新しい演算子を使用する場合、回線継続のサポートについて質問があります。 最初はサポートしないことをお勧めします。

オペレーターソリューションの代わりにコマンドレットソリューションが提案されました。 パイプラインを一重引用符で囲んだり、特殊文字をエスケープしたりする必要があるため、これでは「カットアンドペースト」の問題は解決されないと考えています。 Invoke-NativeCommand (名詞は未定)のようなコマンドレットは、演算子の必要性を置き換える代わりに、追加のオプションとして役立つと信じています。

関連する問題

これにより、次の問題も解決するはずです。

https://github.com/PowerShell/PowerShell/issues/12491
https://github.com/PowerShell/PowerSHell/issues/1761

Committee-Reviewed Issue-Discussion Issue-Enhancement

最も参考になるコメント

モジュールNativeInstall-Module Native -Scope CurrentUser )を公開しました。これ上記の@rkeithhillのコメントからのものです。

概念的な霧をクリアしたい場合は、ユースケースを別の方法で組み立てる必要があると思います。
_それらのどれも解析の変更を必要としません_。

ユースケース[ネイティブシェル呼び出し]:

プラットフォームネイティブシェル用に作成された_個別コマンド_(ユースケース1)または_マルチコマンドコマンドライン全体_(ユースケース2)を実行する必要があります_(この問題):

  • 別のシェルの構文を使用しているため、_it_が解析を実行するために、コマンド(行)を_単一の文字列として_ターゲットシェルに渡します。 PowerShellの文字列補間は、渡された文字列にPowerShell値を埋め込む機能を提供します(ユースケース2a)。
  • insInvoke-NativeShellは、これらのユースケースをカバーしています。
# Use case 1: Single executable call with line continuation, on Unix.
@'
tar -cvpzf /share/Recovery/Snapshots/$(hostname)_$(date +%Y%m%d).tar.gz \
    --exclude=/proc \
    --exclude=/lost+found 
'@ | ins

# Use case 2: Entire Bash command line (also with line continuation)
@'
ps -o pid,args | awk \
  '/pwsh/ { print $1 }'
'@ | ins

# Use case 2a: Entire Bash command line (also with line continuation) with string interpolation.
# Note the double-quoted here-string and the need to escape the $ that is for Bash as `$
$fields = 'pid,args'
@"
ps -o $fields | awk \
  '/pwsh/ { print `$1 }'
"@ | ins

# Alternative to use case 2a: pass the PowerShell value *as a pass-through argument*,
# which allows passing the script verbatim.
# Bash sees the pass-through arguments as $1, ... (note that the `awk` $1 is unrelated).
@'
ps -o $1 | awk \
  '/pwsh/ { print $1 }'
'@ | ins - 'pid,args'

here-string構文は最も便利ではありませんが(したがって、インラインバリアントを実装することをお勧めします-#13204を参照)、それを使用する必要はありません。 逐語的なコマンドの場合、 '...'使用できます。これには、_doubling_埋め込み'が存在する場合にのみ必要です。

また、これは「StackOverflow演算子」の合理的な代替手段です

次のPSReadLineキーハンドラーを$PROFILEファイルに配置すると、 Alt-vを使用して、逐語的なhere-stringを使用してinsへの呼び出しをクリップボードに入れることができます。現在のクリップボードのテキストが貼り付けられる場所。Enterは通話を送信します。

# Scaffolds an ins (Invoke-NativeShell) call with a verbatim here-string
# and pastes the text on the clipboard into the here-string.
Set-PSReadLineKeyHandler 'alt+v' -ScriptBlock {
  [Microsoft.PowerShell.PSConsoleReadLine]::Insert("@'`n`n'@ | ins ")
  foreach ($i in 1..10) { [Microsoft.PowerShell.PSConsoleReadLine]::BackwardChar() }
  # Comment the following statement out if you don't want to paste from the clipboard.
  [Microsoft.PowerShell.PSConsoleReadLine]::Insert((Get-Clipboard))
}

ユースケース[直接実行可能呼び出し]:

_PowerShell_の構文を使用し、_個別の引数_を使用して_単一の外部実行可能ファイル_を呼び出します(ユースケース1aおよび3)。

  • これはあらゆるシェルの中心的な使命であり、堅牢に機能することが非常に重要です。

    • PowerShellが、_its_を_as-is_で解析した結果の引数をターゲットの実行可能ファイルに渡すことができることに依存できる必要があります。 現在はそうではありません-#1995を参照してください
  • _PowerShellの_構文と_its_引数モードのメタ文字を理解する必要があります。

    • `がエスケープ文字として、および行の継続に使用されることに注意する必要があります。
    • PowerShellには、逐語的に使用するために引用符/エスケープを必要とする追加のメタ文字があることに注意する必要があります。 これらは( @は引数の最初の文字としてのみ問題があることに注意してください):

      • POSIXのようなシェル(Bashなど)の場合: @ { } ` (PowerShellによる事前の拡張を防ぎたい場合は$
      • cmd.exe( ) @ { } # `
      • 個別に` -そのような文字をエスケープします。 十分です(例: printf %s `@list.txt )。

#1995が修正されるのを待っている間、関数ie (for i nvoke(external) e xecutable)は、直接呼び出しの前にギャップを埋めます。 たとえば、次の呼び出しの代わりに:

# This command is currently broken, because the '{ "name": "foo" }' argument isn't properly passed.
curl.exe -u jdoe  'https://api.github.com/user/repos' -d '{ "name": "foo" }'

次を使用します。

# OK, thanks to `ie`
ie curl.exe -u jdoe  'https://api.github.com/user/repos' -d '{ "name": "foo" }'

Nativeモジュールには、 echoArgs.exeに似たもの、 dbeaDebug-ExecutableArguments )コマンドが付属しています。 Windowsでのサンプル出力:

# Note the missing first argument, the missing " chars., and the erroneous argument boundaries.
PS> dbea '' 'a&b' '3" of snow' 'Nat "King" Cole' 'c:\temp 1\' 'a \" b'
7 argument(s) received (enclosed in <...> for delineation):

  <a&b>
  <3 of snow Nat>
  <King>
  <Cole c:\temp>
  <1\ a>
  <">
  <b>

Command line (helper executable omitted):

  a&b 3" of snow "Nat "King" Cole" "c:\temp 1\\" "a \" b"

-UseIe-ie )スイッチを使用すると、 dbeaieを介して引数を渡すように指示できます。これは、問題が修正されたことを示しています。

# OK, thanks to -UseIe
PS> dbea -UseIe '' 'a&b' '3" of snow' 'Nat "King" Cole' 'c:\temp 1\' 'a \" b'
6 argument(s) received (enclosed in <...> for delineation):

  <>
  <a&b>
  <3" of snow>
  <Nat "King" Cole>
  <c:\temp 1\>
  <a \" b>

Command line (helper executable omitted):

  "" a&b "3\" of snow" "Nat \"King\" Cole" "c:\temp 1\\" "a \\\" b"

注:#1995が修正されると、 ieは不要になります。 上位互換性のために、 ieは、修正を検出して自動的に延期するように設計されています。 つまり、修正が行われると、 ieは回避策の適用を停止し、直接/ &呼び出しのように効果的に機能します。

ユースケース[直接の不正なWindows実行可能ファイル呼び出し]:

_Windowsのみ_で発生する2つの主な問題があります。

  • 最も広く使用されている規則とは異なる引用要件を持つ「不正な」実行可能ファイルを呼び出してmsiexec.exemsdeploy.exeprop="<value with spaces>"を正確にそのように引用する必要があります-_value_部分のすぐ周りの引用- "prop=<value with spaces>" -全体の引用引数-_should_は同等です(後者は、PowerShellが-当然のことながら-舞台裏で行うことです)。

  • スペースを含まないが、 &^|などのcmd.exeメタ文字を含む_an引数を使用して_バッチファイル_を呼び出しています。 例えば:

    • .\someBatchFile.cmd 'http://example.org/a&b'
    • PowerShellは-当然のことながら- http://example.org/a&b _unquoted_を渡します(空白が埋め込まれていないため)が、 cmd.exe -不当に-バッチファイルに渡された引数をリテラルとして受け入れるのではなくcmd.exe内部に適用されるのと同じ解析規則。

    • 注:バッチファイルを使用して機能を_直接_実装することはおそらく衰退していますが、バッチファイルaz.cmdとして実装されるAzureのaz CLIのように、それらを_CLIエントリポイント_として使用することは依然として非常に一般的です。

注: ie 、バッチファイル、 msiexec.exeおよびmsdeploy.exeこれらのシナリオを自動的に処理するため、_most_呼び出しの場合、追加の作業は必要あり

これを解決するには、次の2つの方法があります。

  • cmd.exe与えられた場合、コマンドラインの引数に独自の解釈を適用した後、指定されたとおりに引用符を保持します。Windowsでins呼び出しに委任できます。

    • ins '.\someBatchFile.cmd "http://example.org/a&b"'
    • _expandable_文字列を使用する場合、これにより、PowerShell値をコマンド文字列に埋め込むことができます。

      • $url = 'http://example.org/a&b'; ins ".\someBatchFile.cmd `"$url`""

  • または、現在の--%実装を使用しますが、その制限に注意してください。

    • .\someBatchFile.cmd --% "http://example.org/a&b"'
    • --%実装方法を考えると、PowerShell値を埋め込む唯一の方法は、厄介なことに_auxを定義することです。 環境変数_そして%...%構文でそれを参照します:

      • $env:url = 'http://example.org/a&b'; .\someBatchFile.cmd --% "%url%"


エラー処理

保留中のhttps://github.com/PowerShell/PowerShell-RFC/pull/88は、外部(ネイティブ)実行可能ファイルとのエラー処理の統合を改善します。

それまでの間、 Nativeモジュールには、ゼロ以外の終了コードをスクリプト終了エラーとして扱うアドホックオプトイン用の2つの機能が付属してい

  • ins-e / -ErrorOnFailureスイッチをサポートします。これは、ネイティブシェルの呼び出し後に$LASTEXITCODEがゼロ以外の場合にエラーをスローします。

  • ieeは、 ieラッパー関数であり、外部実行可能ファイルの呼び出し後に$LASTEXITCODEがゼロ以外の場合、同様にエラーをスローします。

モジュールに付属するコマンドには多くの微妙な点があります。
かなり広範なコメントベースのヘルプが、うまくいけばそれらを十分にカバーしています。

全てのコメント189件

私はこのアイデアが好きで便利だと思いますが、単一の文字列拡張を取得できれば、はるかに便利だと思います(DSLの場合は特に考えています)。 したがって、PSでcmd.exe互換の文字列を作成した場合は、cmd.exeに逐語的に文字列を付ける方法があります。 おそらく

&n -command $string

それは潜在的に私の通訳を指定することもできます:

&n -shell /bin/sh -command $string
または
&n -shell cmd.exe -command $string

名前/演算子に関しては、「&!」です。 使用中で? これはshbang( "#!")と類似しています。

$!は良い提案です!

シェルは、コマンドとして指定するだけで指定できます。

&! /bin/sh -c blah

$var展開は、 $がネイティブコマンド/シェルに渡されるためにリテラルである必要があるかもしれないという問題を引き起こします。 これが回避しようとする問題の1つは、人々がすべてを適切に脱出する方法を理解する必要がある場合です。 変数の拡張が必要な​​場合は、いつでも次のことができます。

$mycommand = "/bin/sh ls"
Invoke-Expression "&! $mycommand"

ただし、PowerShellとネイティブコマンドを混在させたい場合は、現在の構文を使用し、高度な使用法を検討するため、適切にエスケープする必要があるものに注意するのがおそらく最善です。

$mycommand = "/bin/sh ls"
Invoke-Expression "&! $mycommand"

あなたがiexを提案したとは信じられません。 :-)

@essentialexchそれが適切な場合がいくつかあります:)

この例では、ユーザーが実行する前に$mycommandの内容を適切に検証することが期待されていることに注意してください。

あなたが説明したような問題の素晴らしい記事と解決策が絶対に必要です。
私自身は--%について知りませんでしたし、残念ながらそれを見たことはありません。 したがって、提案された&n演算子は、同様の検出可能性の問題に悩まされる可能性があり、記号と文字を組み合わせるのは自然に見えません(C printfステートメントの%fを思い出させます)。 とにかく重大な変更なので、たとえば&&にできない理由はありますか?
実行したい領域をマークするために角かっこ(または二重中かっこ?)のようなものを使用する方が直感的かもしれません。 例: & [ wsl ls ] | less

&!が他のシェルからのものを取得するためのより直感的な方法であることに同意しますが、super-duper-linterでは通常、パラメーター配列を作成してコマンドにスプラットすることでネイティブコマンドを実行しています。

$command = 'linter'
$myargs = @(
    '-config'
    'linterconfig.path'
)
if ($Test) {$myargs += 'test'}
& $command <strong i="7">@myargs</strong>

だから、これは条件付きの場合の最良の方法であり、私にとってはそうではありません

@bergmeister私はもともと&&を視覚的には、今日多くの人が知っている&似ていると思っていました。 ただし、パイプラインチェーン演算子である&&は、それが何をすべきかについて混乱を引き起こす可能性があります。 私は現在&!提案が好きです。

@JustinGrote 、それを使い続けない理由はありません。 &!構文は、実際には、切り取って貼り付けたい場合や、PowerShell構文と競合する引数があり、適切にエスケープする方法がわからない場合に適しています

ああ、10年前にブルースとジェイソンと話し合ったのを覚えています。 私の直感では、ここでは別のオペレーターを発明する必要はないようです。 このスレッドの何人かの人々が--%について聞いたことがないことを私は知っています、しかし私はあなたが思っているより多くがあるより賭けます。 どうしたの:

# run ls in wsl, return results to powershell, then pipe to wsl again, to grep.
& wsl ls | wsl grep -i "foo"  

#  the entire pipeline right of wsl will run in wsl. 
& --% wsl ls | grep -i "foo"

なぜ誰もこれを提案しなかったのですか? 「これ以降はすべて、特別なPowerShell処理なしで渡される」と言うことは、他の場所での--%使用法と論理的に一致しています。

@oisingは、実行したいコマンドを前に付ける必要があるため、そのコマンドは機能しません。機能を追加することを提案していますか?
image

これはちょっと期待されていることをします:
function Invoke-LiteralCommand ($command) {Invoke-Expression "& $command --% $args"}

Invoke-LiteralCommand ping -W 200 www.google.com | grep icmp

@JustinGroteはい、今は機能しないことはわかっています:) &n&!などの話題の_代わりに_を提案しています。 私にはもっと理にかなっています。 &は呼び出しであり、 --%はPowerShellの解析を抑制します。 一緒にそれらは首尾一貫していて、何か新しいものを追加するよりも発見しやすいです。 「call」と「callnative」の演算子を使用するというアイデアは好きではありません。

違いを示すために例を拡張しました。

@oisingこれは、新しい演算子を使用することでかっこいいと思いますが、これは「bashを知っている新しいPowerShellユーザー」の入力が非常に鈍いためです。

@oisingこれは、新しい演算子を使用することでかっこいいと思いますが、これは「bashを知っている新しいPowerShellユーザー」の入力が非常に鈍いためです。

どういたしまして。 これは、PowerShell / cmd.exe / bash間の複雑な引用規則を理解していないPowerShellユーザー向けです。 問題のタイトルに「ネイティブを呼び出す」と記載されているように、ネイティブの実行可能ファイルを呼び出すため。

@oisingこれは、新しい演算子を使用することでかっこいいと思いますが、これは「bashを知っている新しいPowerShellユーザー」の入力が非常に鈍いためです。

どういたしまして。 これは、PowerShell / cmd.exe / bash間の複雑な引用規則を理解していないPowerShellユーザー向けです。 問題のタイトルに「ネイティブを呼び出す」と記載されているように、ネイティブの実行可能ファイルを呼び出すため。

本当です、またはそれらについてまったく考える必要がない私たちにとっては。

ええ、私は@oisingと一緒です。 この概念は存在します、それはただひどく不十分です。 まったく新しいものを実装する場合は、古い構文を非推奨/削除することをお勧めします。

私はしばしばこれらのアイデアが表明されていると感じます、彼らの実際のターゲット人口統計に十分な重みが与えられていません。 ユーザーが既存のメソッドを見つけるのに_すでに_苦労していて、見つかったときに不足している既存のメソッド見つける場合は、a)ドキュメントを改善し、b)既存の演算子の実際の機能を改善する必要があります。

代わりに、奇妙なオプションc)を取得します。これは、ユーザーが自然に見つけるのに十分にアクセスできないドキュメントに依存している_another_演算子を導入しながら、過去の問題に何らかの形で対処することになっいます。

これらの概念を紹介するために、エラーメッセージや提案システムを使用する必要があることに同意します。 3分の1が必要だということに同意しませんか? 第4? 5番目? (私は文字通り数を失いました、誰かがここで私を助けてくれます)コマンドを呼び出す方法。 既存の方法では不十分です。つまり、ユーザーが掘り下げ始めたときにユーザーをさらに混乱させるために、クモの巣のように残してはいけません。

何かをする5つの方法があることに人々が気付いたときに私がよく受ける最初の質問は、「文字通り同じことをするがうまく機能しない2〜3の方法があるのはなぜですか」です。私の答えはいつものようです- -PSチームは、機能を追加/改善しようとするときに、過去10年間++のすべてが引き続き機能することを確認することに焦点を合わせすぎています。 ここでもう一度見てみましょう。修正と改善が必要な既存の実装は不十分です。提案された解決策は、不完全な可能性のある別の実装を追加して、プールをさらに泥だらけにすることです。

IMOという別の実装を最初からやり直すのではなく、開始したことを終了する必要があります。

&をいくつかのユニークなユースケースで使用する場合は、これを動詞と見なすか、言語全体の標準化を検討する必要があると思います。

私が最後に望んでいるのは、&が何をするのかについての混乱です。 全体として。

私は3つのシナリオを検討します:

  1. 完全拡張-現在のPowerShellの動作。
  2. 完全なリテラル-OPで提案されています。
  3. 部分的な拡張- wsl ls $path引き続き機能します

@ mklement0のコメントはどこにあるのだろうか? :-)

このスレッドを読み始めたとき、私は思いました。 いい案! しかし、コメントを読んだ後、それは私が考え始めました。 私はいつも&コマンド「PS標準に値しない」と「PERL日」を思い出させる何かを見つけました(ugh)。別の非標準PSコマンド(名詞-動詞ではない)を導入しても役に立ちません。確かに、 PS。

-%パラメータについても知りませんでした。 解決策として、 @ JustinGroteと同じ原則を使用します。

コマンドをPSシェルにカット/ペーストすることは、私の主な「もの」ではありませんでした。
これらのネイティブコマンドをPowerShellのコマンドに置き換える方がよいのではないでしょうか。
cmd.exeを完全に置き換えるためのパスを作成します...

私は既存のコマンドの改善を探求することに投票します。 そして-確かに-%と使用法に関するいくつかのドキュメントを改善する

@iSazonov @ SteveL-MSFTが提案しているユースケースは、「カットペースト」シナリオです。 部分的な拡張は物事をはるかに難しくすると思います(物事のAST側で)

「#!」のすぐにその後 "!#"。 「&!」が好きです。

おそらく、トークナイザーの関数呼び出しにトークンアクセラレータを追加することを検討できます。 これにより、以下を使用できるようになります。

Iex -l
またはInvoke-Expression-通過する前に解析を停止するリテラル。

解析レベルで一意のトークンを追加すると、参入障壁が高くなり、この機能の発見可能性が低下するように感じます。

Get-Help&たとえば、何も表示されません。 そして、about_Operatorsでそれを探す必要があります。

ただし、call_operatorには、文書化されていない固有のケースがあります。
&modulename {コマンド}
モジュールをスコープすることができます。 そして、私はもっとあると確信しています。 しかし、その発見可能性は非常に低いため、ネイティブドキュメント内で見つけるのは困難になります。 そして、コミュニティはJSnoverと彼が私たちにクールなことを見せてくれた話を通してのみそれを知っています。

新しいユーザーの観点から、この「機能」がどれほど発見可能であるかを十分に考慮する必要があると私は信じています。新しいユーザーは、pwshコアの新機能を知らなくても、Powershell5でこれを使用しようとすることを覚えておいてください。発見可能性が低すぎます。

既存の動作を変更したいのですが、PowerShellでこのような基本的なAPIを変更すると、多くの問題が発生します。 構成を使用して移行することを検討することもできます。

PS 6がGAになる前は、物事をより直接的に壊すことが可能だったかもしれませんが、正直なところ、それでも下位互換性に対する深刻な脅威でした(Pythonのprint()関数とは異なります)。

サブプロセスに引数を渡すという点では、同期呼び出しとStart-Process呼び出しの両方で、オーバーホールについて議論する問題がすでに発生していると思います。一貫性を保つために、両方を同時に投資する必要があると感じています。 特にStart-Processは、引数の配列を渡すサポートを更新する必要があります。

cmdline argを渡す同期呼び出しの場合、次の4種類の引数の受け渡しが可能です。

  • レガシーになる現在の動作。WindowsではCommandLineToArgvW影響を受け、予期しない結果が発生します。
  • デフォルトの動作。式の値で引数を渡す必要がありますが、通常のベアワードトークンルールを適用するため、 >|コマンドWrite-Host $valによって表示される値である必要があります。
  • エスケープトークンが表示されるまで、すべてのトークンがベアワード文字列として解釈される逐語的な動作。 これは--%が今日行うことになっていることですが、理想的には--% ... %--ように同じ行に埋め込むことができるエンドトークンが1つだけであるはずです。
  • 代替のsh指向のエスケープロジックが適用され、より単純な互換性を可能にするBashreadlineの動作

最初の動作は、2番目の動作を実験的な機能として導入し、それらを交換することによって、徐々に段階的に廃止する必要があると思います。

2番目と3番目の動作には、 &!&#またはおそらく+% ... -%などの独自のシジルがあります。 しかし、逐語的モードの場合、重要な側面は、より多くのトークンが逐語的に取得されるようにエスケープトークンを単純化することだと思います。 ヒアドキュメントに似ています。

リクエストが「この演算子の後のテキストコンテンツは実行するためにOSの「デフォルトシェル」を呼び出す」のようなコピーアンドペーストシナリオに対処することだけである場合。 shellこれを明示的に言わないのはなぜですか?
`` `powerhell
PS>シェルwslls | もっと少なく
PS>(shell wsl ls * .txt)| Select-String Hello

Forth / APLスタイルの不可解な演算子よりも発見可能で、読みやすくなっています。

これが#1995をどのように解決するかは絶対にわかりません: https: //github.com/PowerShell/PowerShell/issues/1995#issuecomment-653174261を参照して

また、WSLの問題は、PowerShellではなくwsl.exe (https://github.com/PowerShell/PowerShell/issues/12975#issuecomment-650353021を参照)の動作の問題です。
(わかりました、PowerShellに問題がありますが、それは#1995です)

ああ、これはhttps://github.com/PowerShell/PowerShell/issues/12975のほぼ複製ではありませんか? 私は本質的にほとんど繰り返すことができるので、そこで私が述べたことは:

@bitcrazed
問題は、varbatimを受信コマンド/スクリプトに渡すコマンドラインの一部を区切る機能がないため、ユーザーが常につまずくということです。
「varbatimに渡されるコマンドラインの部分」とはどういう意味ですか? 1.呼び出された実行可能ファイルに文字のシーケンスを逐語的に渡し、呼び出された実行可能ファイルの引数配列の1つの要素にこの文字シーケンスが含まれるようにします(たとえば、これらの文字は[mainの `argv [1]`で使用できます](https://docs.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?view=vs-2019#command-line-arguments))または2.挿入する[`CreateProcess`の` lpCommandLine`パラメーター](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw#parameters)に逐語的に続く文字のシーケンス- -(1。)を意味する場合、それは本質的にすでに機能しています:
PS /home/User> /bin/echo 'cd / && ls . | cowsay'
cd / && ls . | cowsay
PS /home/User>
(https://github.com/PowerShell/PowerShell/issues/1995で説明されている埋め込み引用符の問題を除いて)one-line-here-stringを追加すると、いくつかのユースケースが改善されると主張することができますが、私は、それは実際にはこの問題のポイントではありません。 これはすでに多かれ少なかれ機能しているので、あなたは(2.)を意味していると思います---(2。)を意味している場合は、それについての私の意見をやや劇的な方法で述べさせてください:追加しないでくださいこのための特別な構文。 これは基本的に `-%`がやろうとしたことであり、これも実装されるべきではありませんでした。 なぜ私はこれに強く反対しているのですか? 1.これはWindowsのみの問題であるため、構文を追加すると、WindowsのPowerShellの構文がLinuxとは異なることになります。 (または、構文はサポートされますが、現在 `-%`の場合であるため、まったく意味がありません)2。Microsoftによって公開されたWindowsのメインコマンドラインシェルがファーストクラスの機能を追加する場合(viaではなく特別な構文を介して)コマンドレット)を使用して、一般的な[コマンドライン解析ルール](https://docs.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?view=vs)に従わない実行可能ファイルを呼び出します。 -2019#parsing-c-command-line-arguments)(ツールが一般的なルールに従っている場合は、(2。)は必要ありません。通常は、(1。)を使用する方がよいでしょう)、コマンドラインの作成者を奨励します["Windowsコマンドラインアナーキー"](https://stackoverflow.com/a/4094897/2770331)を悪化させるだけのこれらのルールに従わないためのツール。 一般的なルールに従う人が少なければ少ないほど、プログラムで外部実行可能ファイルを呼び出したり、クロスプラットフォームコードを記述したりするのは難しくなります。したがって、プログラムの作成者はこれらの一般的なルールに従うように奨励されるべきだと思います。 3.これが一般的な使用例であることを強く疑っています>これはWSLに影響する問題だけでなく、WindowsTerminalのwtコマンドライン呼び出しや他の多くのツールにも影響します。 そのような問題が発生するいくつかの例を追加できますか? WSLの場合、WSLによるコマンドラインの解析は単純に[壊れている](https://github.com/Microsoft/WSL/issues/1746)と言えます(問題は `bash.exe`に関するものでしたが、状況はデフォルトでは、デフォルトの場合は `wsl.exe`)では良くありません-典型的な[コマンドライン解析ルール](https://docs.microsoft.com/en-us/)に従わないすべてのツールを検討しますcpp / cpp / main-function-command-line-args?view = vs-2019#parsing-c-command-line-arguments)が壊れていますが、WSLのデフォルトの動作はIMHOであり、適切に文書化されていません...私は「デフォルト「 `wsl.exe`の動作が壊れています-この応答を書いているときに、` -e`を使用すると、 `wsl.exe`が実際には期待どおりに動作しているように見えることに気付きました。
PS C:\> wsl -e bash -c 'cd / && ls . | cowsay'
 _______________________________________
/ acct bin boot cache cygdrive data dev \
| etc home init lib lib64 lost+found    |
| media mnt opt proc root run sbin snap |
\ srv sys tmp usr var                   /
 ---------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
PS C:\>
したがって、この明示的な使用例に欠けているのは、他の通常のexeと同様に解析されたコマンドライン引数を使用してデフォルトシェルを呼び出すための `wsl.exe`へのIMOパラメータだけです。

この演算子で改善される「varbatimを受信コマンド/スクリプトに渡すコマンドラインの部分」に関する唯一のことは、上記の(2.)の意味であり、前述のように、その方向に発展することは悪い。

あなたがしたいすべてのコピーを行うと、既存のコマンドラインを貼り付けるショートカットである場合は、なぜあなたはコマンドレット(たとえば、追加しないInvoke-Shell呼び出して、 bash -c Linux上およびcmd /c上をウィンドウズ?
その後、あなたはただすることができます

Invoke-Shell @'
whatever existing comandline containg '"quotes"' or whatnot
'@

1行でなければならない場合は、one-line-here-string構文を追加しますが、適切に見つけることができず、すべてを複雑にする特別な演算子を実装しないでください。

そして、これのために#1995を放棄しないでください!

「印章」という言葉を使うと+10ポイント。

&!shellは、「shell」が一般的な英語の単語であるため、shellという名前の既存のコマンドがある可能性があることです。 (実際、私は「shell」という名前の関数と「n」という名前の関数の両方を持っています(したがって、 &nは好きではありません)。

@oising& --%は素晴らしいですが、提案された機能の明確な目的の1つは、 |がネイティブシェルに渡されるものになることを意味することです。 あなたはPowerShellの構文解析に持ち帰るない何か。 また、パイプラインの優先順位を& --%foo $blah --% more argsで異なるものにすると、当惑することになります... & $foo --% more args | blah実行した場合はどうなりますか? したがって、私の意見では、提案された&!は十分に異なっているため、異なる演算子を使用する必要があります。 (言い換えると、提案された機能は関連していますが、 &--%を組み合わせるの

この機能は、「bashを知っている新しいPowerShellユーザー」や「複雑な引用/エスケープルールをすべて知らないユーザー」だけのものではありません。 また、StackOverflowからコマンドをコピーして貼り付けるだけで、すべてをいじる必要がない、最も専門的なユーザー向けです。 これは私にかなり起こります-私が取り組んでいる製品には、物事を行う方法に関する多くのドキュメントがあり、共通語はcmd.exeコマンドです-したがって、%VARIABLE_REFERENCES%などの修正に取り掛かる必要があります。; &!と入力してから貼り付けると非常に便利です。 実際、これが実装されている場合、私はおそらくそれを「StackOverflowオペレーター」と呼ぶでしょう。 :D

@ vexx32 :これは「すべてを支配する一つの指輪」の呼び出し演算子ではありません。 一般的な問題に対処するためのツールボックス内の別のツール。 このツールのためのスペースを作るために既存のツールを取り除くべきではないと思います。 彼らは異なることをします。 ツールボックスにハンマー、ドライバー、ドリル、インパクトドリル、ネイルガンがあると、新しいユーザーが圧倒されるかもしれないことを理解しています...しかし、それらはすべて「1つまたは複数の他のものを介してポーキーなものを突くためのものです」物事」、それらは専門家にとって非常に貴重です。 すべて異なる(関連はあるが)状況で使用されます。

@TSlivede :#1995が別のものであることに同意します。 しかし、私は「これはWindowsのみの問題です」に同意しません。StackOverflowからプラットフォーム固有のコマンドをコピーして貼り付けると、どのOSにも同じように適用されます。 (実際、これは、あるプラットフォームで別のプラットフォームよりも強力な私のような多くの人々にとって非常に役立ちます。私はWindowsテクノロジーに精通しているため、LinuxではSOから多くのコピーと貼り付けを行う傾向があります。)

新しい演算子&!でもInvoke-Shellコマンドでも、他の人ほど強い気持ちはありません...演算子が検索しにくいなどと不満を言う人には同情しますが、私は&!の簡潔さが本当に好きです。

@jazzdelightsmeこれは、「ツールボックス内の別のツール」ではなく、「現在すでに_大丈夫_であり、改善される可能性のある、すでに約3〜5個あるドライバー用の別の非常に特殊なドライバーアタッチメント」であると私は考えています。

@jazzdelightsme 「Windowsのみ」の部分は、おそらく私が最初にそのステートメントを投稿した問題に関連していました-はい、

#1995が放棄されず、ここで要求された機能が特別な構文ではなくコマンドレット(または、この特別な場合だけでなくどこでも機能する1行のここの文字列の新しい構文)によって解決されない場合、私は実際に賛成ですこの機能を追加します。 (または、「賛成」ではなく、「これは私には完全に受け入れられます」)

別のアイデア:これが実際にネイティブシェル向けの完全なコマンドのコピーと貼り付けに関するものである場合、PsReadLineは、コマンドをbashまたはcmdスタイルからpowershellに大まかに変換する機能を追加できます。 変換は、特別なキーの組み合わせによってトリガーされるか、コマンドの実行中に解析エラーが発生した場合に自動的にトリガーされる可能性があります。

これには、PowerShellの構文をユーザーに教えるという追加の利点があります。

検出可能性について:PsReadLineは、構文的に正しくないコンテンツ(翻訳後に有効)が貼り付けられると、特定のキーの組み合わせを使用できるというメッセージを常に短時間表示できます。

しかし、これを実現するのが少し複雑であるかどうかは理解できました。

@jazzdelightsme @joeyaielloと話しましたか? 彼だけがそれをStackOverflow operatorと呼んでいると思ったので、それは非常に真実ですが、私はうんざりしました

@ SteveL-MSFTいいえ、これについては誰とも話しませんでした。 独立して「StackOverflowoperator」にたどり着きました。 xD

@jazzdelightsme

...提案された機能の明確な目的の1つが、次のことを意味することを除いて| ネイティブシェルに渡されるものになります。 PowerShellの解析に戻るようなものではありません。

あなたが私の提案を理解したかどうかはわかりません。 あなたの言うことは私が言っていることです。 戦略的に大文字のヒントをいくつか使って、もっと冗長にしましょう:D

# NON-OPTIMAL SOLUTION: run "ls" in wsl, return results to powershell, then pipe to wsl again, to "grep."
& wsl ls | wsl grep -i "foo"  

# NEW SOLUTION: the entire pipeline/string, INCLUDING THE PIPE SYMBOL, right of wsl will be executed in wsl. 
& --% wsl ls | grep -i "foo"

# NEW SOLUTION: the entire pipeline AS ABOVE is sent to WSL, then the results are returned to powershell
# and piped, in powershell, to foreach-object
(& --% wsl ls | grep -i "foo") | % { "match {0}" -f $_ }

# NEW SOLUTION: allow placing --% beyond first argument
# pass everything right of --% to the command in $wsl 
$wsl = gcm wsl
& $wsl --% ls | grep -i "foo"

# or

& wsl --% ls | grep -i "foo"

# NEW SOLUTION: execute multiline pasted code without powershell parsing.
& --% @'
(pasted multiline code)
@'

ここで何が欠けていますか? パイプが--%後に表示される場合、それは単なる別のばかげた文字、つまり引数です。 演算子の優先順位をいじることはありません。 ネストされたパイプラインまたは部分式に含まれている場合は、PowerShellの解析を再開します。

&$ foo-%more args | 何とか?

さて、それは$foo引数を実行しようとし、 "more""args""|""blah"を渡して何でも処理されます$foo欲しいです。 ルールは私には十分単純に思えますが、確かに私は長い間PowerShell / Monadを使用してきました。 & $foo --% ...--%他の引数と同じように扱うため、これは&への大きな重大な変更ではありません。 したがって、この印章を他の場所で悪意を持って使用していない限り、安全であるはずです。

考え?

--%部分的な行の評価、複数行の評価、および変数の配置をカバーするために、上記に複数の編集を加えました。 新しいシジル、演算子、または奇妙な構文を導入することなく、すべて。 それでカバーできると思います。 唯一のことは、パーサーがそれを処理できるかどうかです。 @lzybkr @JamesWTruher @BrucePayはどう思いますか?

聞いて、聞いて、@ TSlivede。

率直であることをお許しください。しかし、私たちはこれらの問題について長い間話し合ってきました。

この問題が提案することは、魔法の思考に相当します。
これは、運命が悪く、本質的に問題のある「解析停止シンボル」 --%に関連しており、現在の形式では、Windowsでは使用が制限されています(https://github.com/MicrosoftDocs/PowerShell-を参照)。 Docs / issues / 6149)、_ Unixライクなプラットフォーム_では事実上役に立たない(https://github.com/MicrosoftDocs/PowerShell-Docs/issues/4963を参照)。
--%は決して実装されるべきではなく、この提案も提示されたとおりに実装されるべきではありません。

魔法の思考は、2つのアイデアの概念的に混乱した混乱です。

  • (a)「 &|などのシェルのメタ文字を気にすることなく、ベアワードを許可して、スペースで区切られたトークンを外部プログラムに渡したい。」 -https //github.com/PowerShell/PowerShell/issues/12975#issuecomment-646276628を参照して

    • もちろん、そのような機能は、そのようなコマンドを_パイプラインの一部として_または_パイプラインチェーン演算子_( &&および|| )を使用し、同じ行に追加のコマンドを配置することとは相容れません。 ; -そして、特に、コマンドラインで_PowerShell変数と式_を使用できるようになります。
  • (b)「コマンドラインを_通常使用するシェル(またはコマンドラインが最初に記述されたシェル)から_慣れている方法で処理したい」これはもちろん、引用符で囲まれていない文字の使用の対象となります&|はメタ文字として解釈されるため、_構文_の意味があります。

    • 適切な例: cmd/bin/sh (またはbashなどのPOSIXのようなシェル)も、 lsを通過する方法でwsl ls | lessを受け入れません。 ls| 、およびless _ verbatim_からwsl -これらはすべて_unquoted_ |を_their_パイプシンボルとして解釈します。

これらのアイデアは互いに対立しており、明確な解決策が必要です。どちらも特別な構文自体は必要ありません。

  • (a)の解決策は、アイデアを_放棄_し、代わりに_PowerShell独自の既存の構文_を使用して、メタ文字が_verbatim_で使用されるようにすることです。これには、常に_quoting_または_escaping_が必要です。

    • いずれか:メタ文字を含むベアワード(引用符で囲まれていないトークン)を_全体として_: wsl ls '|' less
    • または: ` -メタ文字をベアワードで_個別に_エスケープ: wsl ls `| less
    • または:_array [variable] _を使用して引数_verbatim_を渡します: $wslArgs = 'ls', '|', 'less'; wsl $wslArgs
    • もちろん、#1995は、残念ながら、このアプローチは、外部プログラムを呼び出すときに_埋め込み_ " _-_これに対処する必要がある_:以下を参照する引数に関しては、常に破られていることを示しています。
  • (b)の解決策は、実際に_私が通常使用するシェルを_呼び出し_、コマンドラインを_単一の文字列として_渡すことです。

    • @TSlivedeが示唆しているように、コマンドラインを_単一の文字列として_渡し、_platform-native shell_を呼び出すInvoke-Shellコマンドレットが解決策です-そして、逐語的な文字列の構文がすでにあります( '...'またはそのhere-stringバリアント、 @'<newline>...<newline>'@
    • Unixライクなプラットフォームでは、 Invoke-NativeShellと呼び、 bashではなく/bin/shと呼ぶことをお勧めします。

      • さらに、 insを簡潔なエイリアスとして定義することをお勧めします。

    • このアプローチは、 --%と手元の提案ですべての概念上の問題を解決します。

      • ネイティブシェルに渡されたコマンドがどこで終了するかが非常に明確になり(_単一の文字列_であるため)、通常のPowerShellパイプラインでInvoke-NativeShell / ins呼び出しを使用できます。あいまいさのないPowerShellリダイレクト。

      • _PowerShell_変数値をコマンドラインに埋め込むために、オプションで_expandable_文字列( "...."またはそのhere-stringバリアント)を使用できます( --%では実行できないこと)。


下位互換性が損なわれないように#1995を修正できないと結論付けられた権限があるため、既存のすべての回避策が機能しなくなります。https: //github.com/PowerShell/PowerShell/issues/1995#issuecomment-562334606を参照して

したがって&!などの特別な構文は、 @ TSlivedeのRFCで提案されている動作に基づいて、 #1995に対処するために、外部プログラムに引数を適切に渡すためのオプトインとしてのみ提供する必要があります。 https://github.com/PowerShell/PowerShell-RFC/pull/90。 将来のPowerShellバージョンで下位互換性を破ることが許可されている場合、この動作を示すのは直接呼び出し/ &を使用した呼び出しです。

ユーザーの観点からすると、これは次のことを意味します。_PowerShellの_構文要件を満たすだけです-https //github.com/PowerShell/PowerShell/issues/1995#issuecomment -640711192を参照して

たとえば、次のコマンド-現在意図したとおりに機能しません(直接または&呼び出された場合-このドキュメントの問題を参照してください)-が機能するはずです。

PS> &! bash -c 'echo "one two"'
one two   # Currently (invoked with & instead of &! or with neither) prints only 'one', 
          # because PowerShell passes the entire argument (brokenly) as  "echo "one two"",
          # which the target program sees as *2* verbatim arguments `echo one` and `two`

現在/以前のPowerShellのバージョンでの回避策をお探しの方は、ほとんどのユースケースカバーする簡単な関数を見つけることができますhttps://github.com/PowerShell/PowerShell/issues/1995#issuecomment -303345059を(制限事項がhttpsで議論:// github.com/PowerShell/PowerShell/issues/1995#issuecomment-649560892)、およびhttps://github.com/PowerShell/PowerShell/issues/1995#issuecomment-562334606のより詳細なバージョン

PS :(シンボルベースだけでなく)演算子の発見の問題は、それ自体で対処する価値のある別の問題です:解決策は_演算子のルックアップを可能にするためにGet-Helpを強化することです_-#11339も参照してください暫定ソリューションへのリンク。

下位互換性が損なわれないように#1995を修正できないと結論付けられた権限があるため、既存のすべての回避策が壊れます。#1995(コメント)を参照してください。私たちができる最善のことは、オプトインをサポートすることです。常にデフォルトであるはずの動作を取得するために邪魔にならないようにするための苦痛を最小限に抑えるために、可能な限り簡潔な構文での適切な動作。

@ mklement0オプトインはhttps://github.com/PowerShell/PowerShell/issues/1995の一部であり、拒否されたと思います。 だから私には希望的観測のように聞こえます。 私が間違っている?

@AndrewSav 、当初は構成変数または設定変数を介したオプトインについてのみ説明しました。

ただし、 @ joeyaielloは、問題をクローズしたときにhttps://github.com/PowerShell/PowerShell/issues/1995#issuecomment -653164987で次のように述べています(強調を追加)。

ここで触れるものは、重大な変更ではありません。新しい演算子で問題に対処する必要があります。

新しい演算子は一種のオプトインですが、問題のない演算子です(必要はありませんが、下位互換性の代償です)。

この提案は#1995も解決するとされていますが、(主に)_other_シェルの構文に対応することを目的としているため、解決しません。 両方の問題を個別に解決する価値があることを考えると、私の提案は次のとおりです。

  • 新しい演算子を紹介しましょう。ただし、これを使用して#1995を修正する(https://github.com/PowerShell/PowerShell-RFC/pull/90経由)、つまりPowerShellの_own_(非other-shell-emulating)が壊れていることを修正します。外部プログラムに渡される引数の処理。

    • 新しいコードでは、外部プログラムを呼び出すときに、 &ではなく常に&! (または私たちが決定した形式)を使用する必要があります(外部プログラムの&は非推奨と考えることができます) 。
    • _PowerShell_コマンドを呼び出すと、 &!&ように動作するはずです(問題は発生しませんでした)。これにより、 &!一貫して使用できるようになります。
  • 再利用-コマンドライン-from-other-shellsの問題を解決するために、プラットフォームに適したネイティブシェル(Windowsではcmd /cを呼び出すInvoke-NativeShell / insコマンドレットを実装しましょう。 、 /bin/sh -c (Unixライクなプラットフォームの場合)コマンドラインを_単一の文字列_として渡します。

    • 最も単純なケースでは、コマンドラインに'存在しない場合、通常の単一引用符で囲まれた文字列が機能します。 例えば:

      ins'ls | cat -n '

    • '存在する場合、それらは_doubled_することができます。 例えば:

      ins 'エコー' 'こんにちは' '| cat -n '

    • または、コマンドラインにまったく触れる必要がない場合は、here-stringを使用できます(@TSlivedeですでに示されているように)。この構文は少し面倒ですが、常に機能するはずです。

      ins @ '
      エコー 'こんにちは' | 猫-n
      '@

    • さらに、_expandable_(補間)文字列( "..."または@"<newline>...<newline>"@ )を使用することにより、ネイティブシェルに渡される文字列( --% )に_PowerShell_変数を組み込むオプションがあります。

      $ foo = 'こんにちは'
      ins @ "
      エコー '$ foo' | 猫-n
      "@

    • 注意:

      • Invoke-NativeShellコマンドレットは、 cmd /c / /bin/sh -c呼び出しのかなり薄いラッパーであり、明らかに自分で直接行うことができますが、必要がないという利点があります。特定の実行可能ファイル名とコマンドライン受け渡し構文を知っている。
      • 潜在的に有益な副作用として、 -OutVariableなどの一般的なパラメーターを使用できるようになり、 -Error*パラメーターを_stderr_に作用させるかどうかを検討できます(ただし、対称性のために、 Invoke-Commandすべきであり、これは重大な変更になります)。

        • POSIXのようなシェルは-c _multiple_引数をサポートするため、最初に実行するコードを構成し、後続の引数は$0 (!)で始まります-例: bash -c 'echo $@' _ 1 2 3 -オプションの追加引数もサポートする必要があります。

        • プラットフォームネイティブシェルが呼び出されているため、 cmdshの基本的な違いにより、このような呼び出しは定義上移植性がありません。これが、PowerShellの_own_引数の受け渡し(#1995)を修正することが非常に重要である理由です。これにより、外部プログラムを呼び出すための信頼性の高い、真にクロスプラットフォームの方法が提供されます。


パズルの最後のピースは_documentation_です。

https://github.com/MicrosoftDocs/PowerShell-Docs/issues/5152は、外部プログラム( about_Native_Calls )の呼び出しに関する概念的なヘルプトピックを作成するための長年の提案です。外部プログラムの呼び出しに関連するすべての側面をカバーします。 すでにそこで説明されていること(追加のメタ文字による構文の落とし穴、生のバイトパイプラインの欠如、PowerShellエラー処理との非統合など)は別として、目前の問題についても説明する必要があります。

  • " (および_empty_引数)が埋め込まれた引数の受け渡しが、以前のバージョン(現在は別の提案https://github.com/MicrosoftDocs/PowerShell-Docsで説明されています)でどのように壊れているか/ issues / 2361)、およびそれを回避する方法(手動\ -#1995のヘルパー関数の1つをエスケープまたは使用します。そのうちの1つは、トピックに直接含めるのに十分簡潔です)。

  • 適切な引数の受け渡しを確実にするために、ネイティブ(外部)実行可能ファイルを呼び出すために今後&!のみを使用する方法。

  • Invoke-NativeShell / insを使用して、プラットフォームネイティブシェル用に作成されたコマンドラインをそのまま実行する方法。

興味深いことに、今日のユーザーは次のことができます。

  1. 直接呼び出し
  2. &演算子
  3. 開始プロセス

ユーザーが使用すべきかどうかはまったく明確ではありません。

壊れた動作を修正した後、ユーザーは次の機能を利用できるようになります。

  1. 直接呼び出し
  2. &演算子
  3. 開始プロセス
  4. &! オペレーター
  5. 開始-ProcessV2

シェルがping 127.0.0.1を実行するのは多すぎませんか?

ええ、それは@iSazonovと同様にさらに別の演算子を追加することに関する私の主な関心事です。 それはすでに混乱しています、そしてこれは助けにはなりません。 ドキュメントはパズルの一部にすぎません。 きちんとしたドキュメントがあったとしても、それを行うための_5つの異なる方法_があり、それぞれが少し異なる動作をするという単なる事実は、常に混乱を引き起こします。

UXにまったく関心があるのであれば、さらに追加するよりも既存のケースを改善することを選択する必要があります。

UXにまったく関心があるのであれば、さらに追加するよりも既存のケースを改善することを選択する必要があります。

下位互換性が必要なため、これはできません。 輪になっていく気がします。 https://github.com/PowerShell/PowerShell/issues/1995はそれであり、まさにその理由で閉鎖されました。

@iSazonov

新しいオペレーターを導入しなくても、既存のガイダンスの欠如に対処する必要があります。

簡単に要約すると:

  • Start-Processを使用して_console_(ターミナル)プログラムを呼び出さないでください(Windowsでのみ使用可能である場合を除き、_新しいウィンドウで_実行する必要があります)。

  • 直接呼び出しと&を介した呼び出しは_同等_です。 (スクリプトブロックは別として) &は、コマンド名またはパスが_quoted_であるか、_variablereferences_を含む場合は常に_syntactic_の理由でのみ必要です。


壊れた動作を修正した後、ユーザーは次の機能を利用できるようになります。
直接呼び出し

  • &演算子
  • 開始プロセス
  • &! オペレーター
  • 開始-ProcessV2
  • いいえ、 Start-ProcessV2はなく、_新しいパラメーター_、 -IndividualArgumentsます-https ください

  • はい、 &! (または私たちが決定したシンボル)がありますが、それは実質的に&と直接呼び出しの両方に取って代わります(少なくとも_外部プログラム_では_、しかしあなたはそれを使用することができます) _all_コマンドフォームを使用)-これは簡単に伝達できるはずです。

シェルがping 127.0.0.1を実行するのは多すぎませんか?

ping 127.0.0.1は引き続き機能しますが、 bash -c 'echo "one two"'を機能させるには、次を使用する必要があります。
&! bash -c 'echo "one two"'

これは残念なことですが、直接呼び出し/ &動作を_修正できない_ことを考えると、最善の解決策として私を驚かせます。

幸い、覚えておくのは簡単なルールです。_予測可能な引数を外部プログラムに渡す場合は、 &! _を使用します。

オプトインの代替形式(構成( powershell.config.json経由)または設定変数)は、はるかに問題があります。

  • プリファレンス変数の動的スコープにより、オプトインを設計されていないレガシーコードに誤って適用することが容易になります-https ください

  • 構成はセッション全体に適用され、オプトアウトは完全に不可能になります。

  • どちらの場合も、特定の呼び出しとは_別の_アクションが必要であり、特定の呼び出しを見ても、それがどのように動作するかはわかりません。対照的に、 &!は、どの動作が発生するかについて疑いを残しません。

エンドユーザーには、電卓を起動して、加算操作用の5つのボタンを見つけたのと同じくらいひどいように見えます。 😄

このような複雑な問題に備えるために大幅に改善したい場合は、動作を簡素化してV8.0をリリースするために、(直接呼び出しと& )重大な変更を受け入れるにはおそらくこれで十分です。

私たちの欲求がそれほど強くない場合は、診断を十分に改善して( prog.exe param1 param2 -WhatifとStart-Process -WhatIfについても同じ)、 testargsプログラムが表示する内容とその方法に関する推奨事項を表示することができます。エスケープを正しく実行します。

スクリプト開発者は、デバッガーのテストと使用に時間を費やす余裕があります。 しかし、インタラクティブセッションでは、どのユーザーもシンプルさ、簡潔さ、明快さを求めており、これがすべてを上回ります。

@iSazonov

次に、動作を単純化してV8.0をリリースするために、(直接呼び出しおよび&の)重大な変更を受け入れるにはおそらくこれで十分です。

あなたは確かに_my_票を持っています-
この規模の変更を行うと、最終的にすべての歴史的な手荷物に取り組むことができます-#6745を参照してください

そんなに改善したいのなら

それをそんなに欲しがる2つの正当な理由があります:

  • #1995、多くの関連する問題、および無数のスタックオーバーフローの質問によって証明されるように、壊れた議論の通過による長年の苦痛を終わらせるために。

  • なぜなら-以前に何度か述べたように-引数を使って外部プログラムを呼び出すことは_あらゆるシェルのコアマンデート_です。

歴史的に、Windowsのみの時代には、有能な外部CLIが不足しているため、それらを適切に呼び出すことができず、PowerShellの壁に囲まれた庭にとどまったユーザー(PowerShellネイティブコマンドのみを呼び出す)は苦痛を感じませんでした。 しかし、時代は確かに変わりました:

私たちは、開発、CI、および展開タスクに不可欠なクロスプラットフォームCLIの豊富な時代に生きています。
PowerShellをシェルとして真剣に受け止めたい場合は、この問題に対処する必要があります。


下位互換性を破ることが許可されたv8.0が発生した場合(指が交差した場合)でも、リリースにはかなりの時間がかかる可能性があり、暫定的な解決策も必要です。

提案されたドキュメントの拡張が必要である限り、すぐに利用できるランタイムソリューションがないため、それらだけでは苦痛を十分に緩和できるとは思いません。

演算子は醜いですが、形式に関係なく、ブレークしないソリューションでは追加の構文(入力する必要があります)が必要です。

&!の代わりに、醜くなく、入力が簡単で、言語を「汚染」しないのは、 iep関数などの簡潔な名前の組み込み_function_を出荷することです。 ( I nvoke- E xternal P rogram)これは、ここに示されてます
(他の機能をラップする関数(例: pause )またはcmd.exeユーザーに対応する関数(例: cd.. [原文のまま])はすでに出荷されていることに注意してください。)

したがって、 bash -c 'echo "one two"'を正しく機能させるには、 iep bash -c 'echo "one two"'呼び出します。
または、おそらくより現実的なシナリオを使用するには:

# Pass JSON to an external utility (Unix example)
# Without `iep`, the embedded double quotes are lost and *broken JSON* is passed.
iep /bin/echo '{ "foo": "bar" }'

繰り返しになりますが、最終的には、下位互換性を維持するためのサービスの_妥協_について話します。これは、エンドユーザーにとって必然的に迷惑です。


診断を改善し(prog.exe param1 param2 -WhatifおよびStart-Process-WhatIfについても同じ)、testargsプログラムが表示する内容と、エスケープを正しく実行する方法に関する推奨事項を表示します。

直接/ &ベースの呼び出しはコマンドレット呼び出しではなく、すべての引数はパススルー引数であると見なされるため、 -WhatIfを共通パラメーターとして扱うこと

このような変更を受け入れる場合は、(また) -DoItRightスイッチ(または--%に似たシンボルベースのスイッチ)をオプトインとしてサポートすることもできます。修正された動作-そしてそれはiep -prefix / &!アプローチよりも悪いと私は思います。

(非破壊的な診断オプションは、現在-WhatIfサポートしていないInvoke-Commandを拡張することだと思いますが、十分に文書化された正しいオプトインを提供する場合行動、これはやる価値がないと思います。)

私は@iSazonovに同意し@ mklement0が述べたように、これを適切に修正する最新のリリースを待つことは非常に長い時間になる可能性があります。私たちの多くは、できるだけ早く解決策を切実に必要としています。 私が見ることができるすべてのために、現在の最良の解決策はただ使用することです
https://github.com/PowerShell/PowerShell/issues/1995#issuecomment -562334606でしょ?

@ mklement0コマンドレットは修正しようとしているのと同じパラメーター変更の対象となるため、iep / invoke-externalprogramがどのように機能するかわかりません。 これはパーサーの問題ですよね? コマンドレット/関数内のすべてを非表示にしようとすると、変更/再構築の意図を元に戻す必要があるため、非常に複雑になると思います。 それとも私は何かが足りないのですか?

@oising

明確にするために:リンクされたiep関数は#1995を修正しますが、この提案の主な目的ではありません(上記で説明したように、追求する価値はないと思います)が、OPで述べられている意図は_また_解決#1995。

1995年は、PowerShellが独自の解析を行った後に逐語的に見られるように、外部プログラムに引数を忠実に渡すために_PowerShell_の構文(別のシェルではない)に依存できることについてです。

PowerShell自体の解析は問題なく、_PowerShell_コマンドに引数を渡す限り問題はありません。

対照的に、_外部プログラム_に引数を渡すことはひどく壊れており、それがiep修正するものです。

最終的に使用されるコマンドラインが構築されるときに、_舞台裏_の引数の_再引用とエスケープ_の欠陥のために壊れています。
https://github.com/PowerShell/PowerShell-RFC/pull/90は、適切な修正を提案しています(下位互換性を処理する方法についての合意がなく、いくつかのマイナーな質問はまだ回答されていません)。最近、適切な再引用とエスケープを実行するためにSystem.Diagnostics.ProcessStartInfo.ArgumentListが導入されました(PowerShell自体の解析から得られた引数のコレクションを渡すだけです)-ちなみに、これは_Windowsでのみ_必要です。 Unixでは、賢明なことに、プロセスの起動時に引数を渡すときに、(シェルの外に)コマンドラインはありません。引数を配列としてそのまま渡すだけです。

要するに:

  • 組み込み関数としてiepを提供することは、適切な修正(重大な変更のコンテキストで)が実装されるまで、外部プログラムに適切な引数を渡すための簡単な一時的なオプトインになります。

  • Invoke-NativeShellinsません一時しのぎ- - _its_構文を使用して、_a異なるshell's_(ネイティブシェルの)コマンドラインを呼び出す方法を提供することに- )コマンドレットは適切な解決策であることがわかり上記

現在、PythonでPERLコマンドの切り取りと貼り付けが期待どおりに実行されない場合があります。 図に行きます。 これは、そこにあるすべてのカッターとペーストにとって大きな不利益になるはずです。 Pythonにはそのための特別な演算子が必要だと思います。

あなたが私の提案を理解したかどうかはわかりません。 あなたの言うことは私が言っていることです。 戦略的に大文字のヒントをいくつか使って、もっと冗長にしましょう:D

# NEW SOLUTION: the entire pipeline AS ABOVE is sent to WSL, then the results are returned to powershell
# and piped, in powershell, to foreach-object
(& --% wsl ls | grep -i "foo") | % { "match {0}" -f $_ }

ここで何が欠けていますか? パイプが--%後に表示される場合、それは単なる別のばかげた文字、つまり引数です。 演算子の優先順位をいじることはありません。 ネストされたパイプラインまたは部分式に含まれている場合は、PowerShellの解析を再開します。

考え?

不足しているのは、外部プログラムへの引数として閉じ括弧を渡す必要があることです。 これは典型的なDWIMアプローチですが、PowerShellはHALではありません。

皆さん、詳細なフィードバックをありがとうございます。 ここで私自身として話します。 私が核心に入る前のいくつかの超ポイント:

  • 私はまだ、まったく新しいものを壊すことを決定するvNext /8.0に参加していません。 下位互換性が重要です。 私はそれが苦痛であることを知っています、そして私はむしろ私たちが戻ってPowerShellがこれまでに犯したすべての間違いを訂正することができる世界に住んでいます。 しかし、PSユーザーの大多数は、SOエッジのケースではひざまずいて、ここで問題にぶら下がっていません。 彼らは同じ回避策を4〜10年間コピー/貼り付けしており、なぜそれが機能するのかを必ずしも理解しておらず、アップグレード時にスクリプトが壊れたときに「間違いを修正」していたことを気にしません。 彼らは「PSの更新が私を壊し、更新を信頼できない」ことを知っているだけで、さらに多くのユーザーが更新と採用を遅らせることになります。
  • この号の何人かの人々は、この号に多くの異なる希望や願望を投影しているかもしれないし、あるいはそれを他の修正と一緒に見ているかもしれないと思います。 #1995を閉じることでそれが悪化したことに気づき、申し訳ありません(ただし、具体的に修正できるかどうかはまだわかりませんが、詳しく見ていきます)。これは本当に「トラップドア」ソリューションであり、新しいユーザーと経験豊富なユーザーの両方を、フラストレーションを募らせることなくすばやくバインドから解放します。 家のPS解析側の修正については、まだ長期的な会話ができるので、すべてに真のクロスプラットフォームソリューションを提供できます。

今、私が読​​んだコメント:

  • #! (デフォルトの場合、ユーザーがインタプリタを指定しない可能性が高いことを考えると、 &!または$!いずれか)に合わせるという提案された要望に警戒しています。 。 $! net <stuff>ようなことをしたい場合、 net.exeは私のインタプリタではありません。また、Windows以外の場合、「ネイティブ」なことは、sh / bash /以前のすべてに渡すことです。実行中のバイナリに渡します。たとえば、Pythonが文字列$! /usr/bin/python *.pyまたは$! python *.py *.pyを解析したくない場合。Bashにグロビングを実行してから渡してもらいたい。 pythonに一致するリスト。
  • @oisingが提案したように、私は演算子として--%を支持し、フロントで使用するためにオーバーロードされています。 発見可能性は問題であり、私たちはすでにこれの発見可能性に取り組んでいることを考えると(今はグーグル対応です! 、私たちはそれでうまくいくと言います(私は@ SteveL-MSFTを作った人でした)別の考慮事項として彼の提案に入れてください)。ただし、質問:ここに&呼び出し演算子も必要ですか? --% native.exe do /some $stuff行を始めてみませんか?
  • @rjmholtここでのあなたのコメントを完全には理解していませんでしたが、実行可能ファイルの--%動作ではおそらく何も変更しないはずですが、私たちはあなたの「新しい実行可能ファイルの前にある場所での動作」。
  • @jazzdelightsmeからこれを読んでください、そして私は強く同意します:

    また、StackOverflowからコマンドをコピーして貼り付けるだけで、すべてをいじる必要がない、最も専門的なユーザー向けです。

    私の考えでは、これはシナリオの大きな側面であり、おそらく最大のものです。 それはSOだけではなく、Bashのようなシェルにいることを前提としたWeb全体のドキュメントでもあります。

  • #1995のようなものが修正されるかどうかに関係なく、a)そのような奇妙なエッジケースのロングテールがあり、b)人を壊さずに修正するのは本当に難しいという点があります。 それは必ずしもすべてに当てはまるわけではありませんが、ここ数年で十分にヒットしたので、人々が飛び込みたくない毛深い状況から抜け出すために、このような「トラップドア」が必要であることが私には明らかです。ネストされたエスケープのうさぎの穴(#1995のようなバグがあり、自分が何を知っているかを知ってわかりました)。

コメントを確認する際に、まだ答える必要のある2つの未解決の質問があると思います。

  1. PowerShellでコマンドセパレーターとその後のすべてを引き続き解析しますか、それともコマンドセパレーターもそのままネイティブシェルに渡されますか?
    ネイティブシェルにすべてを逐語的に渡す必要があると言います。これは現在実行できないことであり、先頭の括弧の@oisingのソリューションは、パイプやパイプラインチェーンなどを引き続きサポートできるという点でソリューションになる可能性があります。 。ネイティブ解析とPS解析を組み合わせて使用​​したい場合(ただし、パーサーに近い方から意見を聞きたい場合)。
  2. オペレーターは何ですか?
    上でほのめかしたように、私は--%好きです@ mklement0のような引数は理解していますが、これを行うと、 --%の技術的な意味が変わります(@ SteveL-MSFTもこの引数を私に与えました)が、私は思いません世の中のほとんどの人は、「cmdで行っていたのと同じことをする」という観点から--%を考えています。 この仮定を「ネイティブシェルがここで行うことを行う」というオペレーターの定義に体系化するのは簡単ではないと思います。

直交して、私たちがサポートしたいかもしれない別のシナリオを考えただけです。

Windowsでは、cmdは(事実上)現在のディレクトリをPATHルックアップに含めます。 ただし、PowerShellでは、現在のディレクトリがPATHない場合、EXE(またはPATHEXT内の何か)を実行するために、ユーザーが./をプリペンドする必要があります。

だから私の未解決の質問は:実際にコマンド文字列全体をcmdに渡したいですか? この演算子を使用してコピー/貼り付けのシナリオを実際に明らかにしたい場合は、答えは「はい」であると提案します。一部のサードパーティのドキュメント/チュートリアルでは、使用する予定のツールの配置方法が必ずしも詳しく説明されていないためです。 PATH 。 どちらにしてもそれほど問題ではないかもしれませんが、ここで列挙したいと思います。

  • 私はまだ、まったく新しいものを壊すことを決定するvNext /8.0に参加していません。

ええ、トラブルシューティングの方法を信じられないほど困難にすることなく、これらの問題をどのように修正するかはわかりません。 さらに、私はすべてについて知りませんが、複数のバージョンを作成するときに、これらの複雑なバインダー/パーサーの違いをすべて調整する必要はありません。

通常、私が変更を壊すことに反対しているのなら、それは他の人々のためです。 しかし、これは、ITTにいる人々にとってさえ対処するのはおそらくPITAであるように思われます。

  • @oisingが提案したように、私は演算子として--%を支持し、フロントで使用するためにオーバーロードされています。 (...) --% native.exe do /some $stuff行を始めてみませんか?

私は本当にこれが好きです。 理想的には、 CreateProcess / exec呼び出しにできるだけ近い(さらに、nix env varの処理と入出力リダイレクトまたはコンソール接続)。 または、 cmd.exe / bash完全にフォールバックすることもできます。

--%前に&を置くことに固執していません。 少なくとも私の頭の中では、生の--%ディレクティブ/オペレーターのように扱うという考えを正当化できます。 マルチラインはどうですか? --%@"および"@を変数の置換と部分式に許可し、一重引用符@''@リテラルを渡しますか? ヒア文字列がなければ、1行だけですか?

@oisingが提案したように、私は演算子として-%を支持しています

私のために働きます。

ただし、質問:ここに&call演算子も必要ですか?

私がまだ--% & $computedPathToNativeExe foo;@workspace行うことができる限り、それから私は大丈夫です。 これでcall演算子を使用できる必要があります。

ネイティブシェルにすべてを逐語的に渡す必要があると私は言います。それは現在あなたができないことだからです。

同意しました。

この仮定を「ネイティブシェルがここで行うことを行う」という演算子の(-%)定義に体系化するのは簡単ではないと思います。

また同意しました!

また、これは、実行可能ファイルのセッション専用に定義されている実行可能ファイルの前にenv変数を定義する機能を利用する方法である可能性があります(#3316)。

--% JEKYLL_ENV=production jekyll build

ちょっとした考え。

@rkeithhillcall native operatorの考え方は、行がPowerShellによって処理されず、OSの「デフォルトシェル」に逐語的に送信されるというものです。 したがって、この場合、最初の例--% & $computerPathToNativeExe foo;@workspaceは機能しません。 現在の方法を使用し、必要に応じてエスケープする必要があります。 2番目のケース--% JEKYLL_ENV=productoin jekyll buildは正常に機能するはずです。

行はPowerShellによって処理されず、OSの「デフォルトシェル」に逐語的に送信されます

OK、それは合理的なようです。 ただし、この--% JEKYLL_ENV=productoin jekyll buildはLinux / macOSでのみ機能しますが、Windowsでは機能しません。少なくともPowerShellの助けがなければ、機能しません。

現在提案されている@rkeithhillは、OSの「デフォルト」シェルに依存しているため、Windowsでは機能しません。 プロセスのenvvarを宣言するPowerShellの場合、それについて説明するために別の問題が開かれています。

@ PowerShell / powershell-委員会は本日これについて議論しました。私はその議論の結果を反映するために元の提案を更新しました。 実験的な機能の実装を進め、作業コードを使用してユーザーからより多くのフィードバックを取得します。 オペレーターの印章はまだ開いていますが、今のところ--%を使用しています。

ここで、 $fooはリテラルファイル名であり、 $PWDはWSL内の現在のディレクトリです。 最初の例では、PowerShell内ではなくWSL内で実行するには、 &&をエスケープする必要があることに注意してください。

$foo$PWDはどちらも、 shによって評価される変数参照です。

このような実行からの出力をPowerShellにパイプで戻すには、ユーザーは最初に結果を変数に格納する必要があります。

$out = --% ls *.txt
$out | select-string hello

現在の&呼び出し演算子とは異なり、PowerShell構文を使用できないことに注意してください。

--% $commandline

$commandline文字通り( cmd )またはシェル拡張後に( sh下で)実行しようとします。 PowerShellはその変数を解決しようとはしません。

カットアンドペーストの問題は、 &nを入力した後に貼り付けるだけで解決します。

--%後に貼り付けるだけです

上記のwsl例は、次のようになります。

どれ?

--%後のすべての引数は「デフォルト」シェルに渡されるため、PowerShellへのパイプライン化をサポートするには、変数を使用する必要があります。

これは繰り返しです。

何か便利なものを追加する場合は、ピボットを提案します。

herestringリテラルのようなものがないのはなぜですか

@! ""!@

したがって、これを行うための実際の方法を、独自の問題を抱えている-%の代わりに使用できます。

少なくともそうすれば、「より良い」設計戦術で問題を埋めることができます。
そして、これらのエッジケースが解決されるべきAbout_Stringsにあることの発見可能性。

ちょっとした考え。

@!"…"!@Invoke-NativeShell @"…"@よりも優れていることがわかりません。 PowerShellをBrainfuckのようにしようとしていますか?

@ yecril71pl

@!"…"!@Invoke-NativeShell @"…"@よりも優れていることがわかりません。 PowerShellをBrainfuckのようにしようとしていますか?

@ romero126は、1行のherestringリテラルを提案することを意図しており、次のように記述できると思います。

Invoke-NativeShell @!"complicated native command with "quotes" and | pipe"!@

の代わりに

Invoke-NativeShell @"
complicated native command with "quotes" and | pipe
"@

このような1行のherestringを検討する場合は、 @"""…"""@@'''…'''@ような構文を使用することをお勧めします。これは、 @!"…"!@よりもIMOで入力しやすいでしょう。


@ romero126意味を明確にして

@ yecril71plこれらのエラーをキャッチしてくれてありがとう、修正でトップメッセージを更新しました。

--%をコマンドラインとして実行するか、バッチファイルとして実行するかは指定されていません。

@ romero126は、1行のherestringリテラルを提案することを意図しており、次のように記述できると思います。

Invoke-NativeShell @!"complicated native command with "quotes" and | pipe"!@

の代わりに

Invoke-NativeShell @"
complicated native command with "quotes" and | pipe
"@

このような1行のherestringを検討する場合は、 @"""…"""@@'''…'''@ような構文を使用することをお勧めします。これは、 @!"…"!@よりもIMOで入力する方が簡単です。

@ romero126意味を明確にして

文字列に柔軟性を追加して「ほぼ生の」未解析データを処理すれば、このポップアップに関する問題は発生しないと思います。
@TSlivede私はあなたが言ったことにほぼ完全に同意します。 わずかな違いがあります。 引用符内に何も補間せずに、単一行と複数行の両方を処理できる必要があります。 それを実現するために私たちが着手する構文が何であれ、私はオープンです。 私はコンセプトにもっと焦点を合わせています。

これらの例では、文字列を返すだけなので、「Invoke-NativeShell」を実行する必要がない場合に多くの柔軟性が追加されます。 つまり、文字列のように自由に操作できます。 これが潜在的に素晴らしいもののステープルになる可能性があるように。

このようなピボットは、エッジケースを処理できるときに、ほぼ解決策でホイールを回転させる上記の問題に対処する必要がないことを意味しますが、全体として問題に対処します。

簡単な例:

# For this scenario let @!"<text>"!@ be our HereString Verbatim

Invoke-NativeShell @!"complicated native command with "quotes" and | pipe"!@
# or
Invoke-NativeShell @!"
Complicated native command with "quotes" and pipe and <tabs>
"!@

#or 
$r = @!"
complicated native command with custom arguments: {0}
"!@ -format "foo"
Invoke-NativeShell $r

これは、このコメントの2番目の部分にある@ mklement0の問題に対処していません。 問題の事実は、これまでにすべてのコマンドに単一の文字列を渡すことはできないということです。 多くの場合、それらを分割する必要があります。

文字列に柔軟性を追加して「ほぼ生の」未解析データを処理すれば、このポップアップに関する問題は発生しないと思います。

これが'@'目的です。

これらの例では、文字列を返すだけなので、「Invoke-NativeShell」を実行する必要がない場合に多くの柔軟性が追加されます。 つまり、文字列のように自由に操作できます。 これが潜在的に素晴らしいもののステープルになる可能性があるように。

ネイティブコマンドは一連の文字列を返します。 @!"は、理解できないもののステープルになる可能性があります。

文字列に柔軟性を追加して「ほぼ生の」未解析データを処理すれば、このポップアップに関する問題は発生しないと思います。

これが'@'目的です。

これらの例では、文字列を返すだけなので、「Invoke-NativeShell」を実行する必要がない場合に多くの柔軟性が追加されます。 つまり、文字列のように自由に操作できます。 これが潜在的に素晴らしいもののステープルになる可能性があるように。

ネイティブコマンドは一連の文字列を返します。 @!"は、理解できないもののステープルになる可能性があります。

あなたは混乱していると思います。 私が言っていたポイントで。
一重引用符と二重引用符は、$ variableを展開するかどうかだけを拡張します。 文字を自動的にエスケープしません。 それはまた私を制限するので、私はもはやその定義文字を使用することができません。 したがって、代わりに、現在のように正しく機能するようにします。 それでも文字をエスケープする必要があります。これが、&!を含める必要がある理由の全体的なポイントです。 コマンド。

あなたがより良い解決策を持っているなら、私はすべての耳です。 これは、&!を追加するよりも多くのエッジケースに当てはまると思います。

一重引用符と二重引用符は、$ variableを展開するかどうかだけを拡張します。 文字を自動的にエスケープしません。 それはまた私を制限するので、私はもはやその定義文字を使用することができません。 したがって、代わりに、現在のように正しく機能するようにします。 それでも文字をエスケープする必要があります。これが、&!を含める必要がある理由の全体的なポイントです。 コマンド。

どのキャラクターを脱出する必要がありますか、そしてその理由は何ですか?

@ romero126今、私はあなたが言っていることを混乱させています。 PowerShellにここの文字列があることをご存知ですか?

以前は、PowerShellの構文を文字列が煩わしいと考えるかもしれないと思っていましたが(少なくとも、最初と最後に改行が必要だとイライラすることがあります...)、今は何がわからないのですか?あなたが言っている、あなたは明確にすることができますか?

@TSlivede

改善を提案する既存の提案#2337があり、終了区切り文字をインデントできるようにすることに重点を置いていますが、 @ lzybkrhttps:// githubでRustのような_single-line _(-also)バリエーションも提案してい

# `ins` is `Invoke-NativeShell`
ins @' python -c 'print("hi")' | cat -n '@

必要に応じて、_multiple_ '@と組み合わせることで、エスケープの必要性を回避できます(たとえば、 @'' can use @' here ''@

言い換えると、これはPowerShell文字列リテラルの一般的な拡張機能であり、どこでも使用でき、 Invoke-NativeShellも同様に恩恵を受けます。

#2337は主に他のことに焦点を当てているので、 #13204

逃げる必要は避けられます

私はこのスレッドでこれを数回見ました。

新しいモードを開始するためのトークナイザーへのインジケーターには、エスケープメカニズムが必要です。これは、そのモードを終了することをトークンライザーと区別して、その文字のリテラル形式から区別する必要があるためです。

今日の最も自然な形式は、一重引用符で囲まれた文字列です。

  • ' :一重引用符のトークン化を開始します
  • ' :一重引用符によるトークン化を終了します
  • '' :一重引用符で囲まれた文字列内にリテラルの一重引用符を記述します

これにもかかわらず、私たちが脱出について話している理由は次のとおりだと思います。

  • --%演算子は、モードを終了する方法が多すぎて( |&&||; 、改行)、文字列を許可しますその中( '文字を削除)
  • Herestringsとcoは、それらの配列ではなく1つの文字列引数に解決されます

実行可能呼び出しに引数を渡したいということは、実際には配列構文について話していることを意味します。

  • アレイの開始方法(逐語的モードの開始)
  • 配列を分離する方法(新しい実行可能ファイルに単一の引数を渡す)
  • 配列を終了する方法(逐語的モードを終了)

execは配列を想定しているため、これは* nixのネイティブコンセプトです。Windowsでは、配列を取得し、特定の文字列構文にシリアル化して、 CommandLineToArgvW渡す必要があると思います。

つまり、2つのエスケープが必要です。

  • 配列セパレータリテラル
  • 配列終了リテラル

たとえば、次のようにしましょう。

  • コマンドが新しい逐語構文になる前の--%
  • 構文をどのように終了しますか? 改行と;多分?
  • 引数をどのように分離しますか? 多分?

質問は次のとおりです。

  • リテラル;または改行を渡すにはどうすればよいですか?
  • リテラルを渡すにはどうすればよいですか?

ネイティブコマンドラインは配列ではありません。 文字列またはASTのいずれかです。 PowerShellはネイティブシェルのASTについて何も認識しないため、文字列のみが残ります。

ネイティブコマンドラインは配列ではありません。 文字列またはASTのいずれかです

あなたはこの主張の根拠を提供していません。

PowerShellがコマンドのASTを構築する場所は次のとおりです(コマンドがどの種類のコマンドを解決するかは実行時までわからないため、あらゆる種類の):

https://github.com/PowerShell/PowerShell/blob/f82f74d89811e91613a7450e536d652c5d8f784e/src/System.Management.Automation/engine/parser/Parser.cs#L6391 -L6634

コマンド要素(パラメーターと引数を含む)が配列に追加されていることに注意してください。

これは、PowerShellで次のように動作していることがわかります。

> { ping 192.168.0.1 }.Ast.EndBlock.Statements[0].PipelineElements[0].CommandElements

StringConstantType : BareWord
Value              : ping
StaticType         : System.String
Extent             : ping
Parent             : ping 192.168.0.1

StringConstantType : BareWord
Value              : 192.168.0.1
StaticType         : System.String
Extent             : 192.168.0.1
Parent             : ping 192.168.0.1

その配列はここで式にコンパイルされます:

https://github.com/PowerShell/PowerShell/blob/f82f74d89811e91613a7450e536d652c5d8f784e/src/System.Management.Automation/engine/parser/Compiler.cs#L4127 -L4160

そして、それはここでパイプライン呼び出しに渡されます( Expression.NewArrayInit(typeof(CommandParameterInternal[]), pipelineExprs)が引数が渡される場所であることに注意してください):

https://github.com/PowerShell/PowerShell/blob/f82f74d89811e91613a7450e536d652c5d8f784e/src/System.Management.Automation/engine/parser/Compiler.cs#L3798 -L3805

実行時に、コンパイルされた式が実行されると、それがこのメソッド呼び出しになり、

https://github.com/PowerShell/PowerShell/blob/f82f74d89811e91613a7450e536d652c5d8f784e/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs#L29 -L312

最終的に、パイプラインが呼び出されると、その引数配列はNativeCommandParameterBinderを使用してネイティブコマンドにバインドされます。

https://github.com/PowerShell/PowerShell/blob/f82f74d89811e91613a7450e536d652c5d8f784e/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs#L69 -L137

これは、各引数に使用された文字列の種類などのASTメタデータを含む引数配列を取得し、ここのNativeCommandProcessorで引数呼び出し用の新しい文字列を作成します。

https://github.com/PowerShell/PowerShell/blob/f82f74d89811e91613a7450e536d652c5d8f784e/src/System.Management.Automation/engine/NativeCommandProcessor.cs#L1094 -L1166

これが行われるのは、現在プロセス呼び出しに使用している.NET APIが、配列を渡して.NETに呼び出しを再構築させる.NET Coreの新しいバージョンではなく、古い「単一文字列のすべての引数」バージョンであるためです。プラットフォーム固有の方法で必要に応じて。

しかし、そのAPIを使用するのは実装の詳細です。 たとえば、ここで行うように、* nixで直接fork / exec呼び出すことができます。

https://github.com/PowerShell/PowerShell/blob/f82f74d89811e91613a7450e536d652c5d8f784e/src/powershell/Program.cs#L268 -L330

ここでexecは配列をとることに注意してください。これは、syscallに引数を渡す最も簡単で直接的な方法であり、最終的には逐語的な引数構文の目標であるためです。

@rjmholt

_機能的に_、すべてのニーズは既存の文字列リテラル形式ですでにカバーされています。_ネイティブコマンドラインを単一の文字列として渡す場合_。これは、新しいInvoke-NativeShell / insコマンドレットを介して強くお勧めします。

ここでの開始点は、配列ではなく_単一の文字列_です。これは_ターゲットシェルによって_解析される__コマンドライン全体_であり、これをPowerShell--%ようなPowerShellの異なるシェルの構文

Invoke-NativeShellが行う必要があるのは、ネイティブシェルコマンドライン全体を含む単一の文字列をCLIを介してネイティブシェルに渡すことだけです。

  • Unixでは、これは次のことを意味します。 exec渡される引数_array_の2番目の要素として文字列をそのまま_全体として_渡します( -cが最初の引数配列要素であり、 /bin/sh実行可能ファイル); 簡単な例で.NET用語で表されます。ここで、 printf "'%s'" foo | cat -nは、通過するコマンドラインを含む単一の文字列の逐語的な内容です( .Argumentsではなく.ArgumentListの使用に注意してください)。 .Arguments ; 'の倍増は、この例のアーティファクトのみです):

    • $psi = [Diagnostics.ProcessStartInfo]::new('/bin/sh'); $psi.ArgumentList.Add('-c'); $psi.ArgumentList.Add('printf "''%s''" foo | cat -n'); [Diagnostics.Process]::start($psi).WaitForExit()
  • Windowsの場合、これは次のことを意味しcmdの癖に対応するには、 CreateProcesslpCommandLine引数を次のように入力します( lpApplicationNameはの値と見なされます)環境変数ComSpec 、これはcmd.exeを指します): "/c " + cmdLine 、ここでcmdLineはコマンドライン文字列全体です。 簡単な例を使用して.NET用語で表されます。ここで、 echo a^&b & verは、通過するコマンドラインを含む単一の文字列の逐語的な内容です。

    • $psi = [Diagnostics.ProcessStartInfo]::new($env:ComSpec); $psi.Arguments = '/c ' + 'echo a^&b & ver'; [Diagnostics.Process]::start($psi).WaitForExit()

      • @ yecril71pl 、これは、コマンドプロンプトまたはバッチファイルのセマンティクスを使用するかどうかに関する質問への回答を意味します。これは前者であり、Pythonのos.system()などの他のスクリプト言語でも使用されます。 (おそらく不幸な)意味は、 %文字をエスケープできず、 forループ変数は単一の%使用する必要があるということです(例: %i %%i %i代わりに%%i ); また、ループ本体コマンドの前に@を付けて、エコーされないようにする必要があります(たとえば、 for %i in (*.txt) do <strong i="56">@echo</strong> %i )。

このプロセスは_エンドユーザーに対して透過的_であるため、彼らが集中する必要があるのは、ネイティブシェルコマンドライン_verbatim_を渡すことだけであり、_PowerShellの_文字列リテラル構文要件を満たす必要があるだけです。

ins @'<newline>...<newline>'@の形式では、ネイティブシェルのコマンドラインをそのまま使用できます。さまざまな既存の文字列リテラル形式を使用する方法については、上記を参照してください。これは、ここで_interpolating_が利用できるためです。文字列形式( @"<newline>...<newline>"@ )も-コマンドラインで_PowerShell_変数と式を使用する機能が含まれています(使用できないことは--%の主な欠点の1つです)。

私の以前のコメントが提案しているのは、_この提案とは別の__生の文字列リテラルの新しい一般的な形式_です(そしてその解析ロジックは(うまくいけば)明確に定義されています)。 ただし、前述のように、 Invoke-NativeShell呼び出しは_より便利_になります。

すでに実行できることの代わりに( Invoke-NativeShell / insコマンドを想定):

# ALREADY WORKS: Literal here-string
ins @'
python -c 'print("hi")' | cat -n
'@

提案された新しい単一行の生のリテラルを使用すると、次のように簡略化できます。

# PROPOSED, more convenient syntax: new raw literal.
ins @' python -c 'print("hi")' | cat -n '@

この新しい生の文字列リテラル構文の詳細について議論する必要がある場合は、ここではなく、#13204で議論させてください。

したがって、元の意図を理解するために提案を読み直すと、実際には、 /bin/sh -c '<command>' + cmdバージョンのより良い構文と、各ターゲットシェルの特別な文字列エスケープロジックが求められていることがわかります。 私は最初の概念を特別な構文に基づいており、パーサーとネイティブコマンドプロセッサを操作する必要があり、.NETのProcessStartInfo.Argumentsプロパティを引用符の受け渡しに関して正しく使用するのは非常に困難でした

しかし実際には、 Arguments文字列はそのまま渡されます。 したがって、必要なのは、そのような文字列を直接渡すことだけです。

その場合、新しい構文はまったく不要だと思います(トークン化ロジックが複雑になり、混乱する可能性があります)。代わりに、これは単なる新しいコマンド、 insです。 .NETには、ここで再実装を余儀なくされるロジックがいくつかありますが、とにかく少し賢くする必要があるので、それで問題ありません。

@rjmholtのコメントに関するコメントhttps://github.com/PowerShell/PowerShell/issues/13068#issuecomment-660231641

新しいモードを開始するためのトークナイザーへのインジケーターには、エスケープメカニズムが必要です。これは、そのモードを終了することをトークンライザーと区別して、その文字のリテラル形式から区別する必要があるためです。

私は同意し、ここにインラインの文字列構文でエスケープの必要性を完全に回避できるとは思いません。

-%演算子は、モードを終了する方法が多すぎて(|、&&、||、;、改行)、その中の文字列を許可します( '文字を削除します)

--%と言えば、既存の--%スイッチを指しているのですか? もしそうなら、 --%が呼び出し演算子として提案されているので、コメントでそれを明確にすることをお勧めします。

実行可能呼び出しに引数を渡したいということは、実際には配列構文について話していることを意味します。

提案は、ネイティブシェル(shまたはcmd)を呼び出し、 sh -c ...ように、呼び出し演算子--%後にすべてを文字通り渡すことです。 したがって、引数をターゲットの実行可能ファイルに渡すのはPowerShellではありません。 その場合、_配列構文_は必要ないと思いますよね?

構文をどのように終了しますか? 改行と; 多分?
引数をどのように分離しますか? 「スペース」多分?

逐語的な構文解析は改行で終わると思います。 引数の一部として改行を渡すには、bashで直接行うのと同じように、 \nを使用します。

ネイティブコマンドラインは配列ではありません。 文字列またはASTのいずれかです

あなたはこの主張の根拠を提供していません。

PowerShellがコマンドのASTを構築する場所は次のとおりです(コマンドがどの種類のコマンドを解決するかは実行時までわからないため、あらゆる種類の):

この提案が実装されると、PowerShellがASTをまったく構築しない特別な構造が導入されます。

それを聞いてうれしい、@ rjmholt。

.NETには、このためのロジックがいくつかあり、再実装を余儀なくされます。

以前のコメントのコマンドが示すように、実際には何も再実装する必要はないと思います。Windowsでは、WinAPIへのコマンドライン文字列全体のパススルーに.Argumentsを使用します。 Unixでは、 .ArgumentListを使用して、 exec直接使用される引数_array_を作成します。

この提案が実装されると、PowerShellがASTをまったく構築しない特別な構造が導入されます。

それは、この目的のために設計された別のASTタイプを構築するでしょう。 ASTの一部でない場合は、基本的にコメントと同じで、何も起こりません。

_機能的に_、すべてのニーズは既存の文字列リテラル形式ですでにカバーされています。_ネイティブコマンドラインを単一の文字列として渡す場合_。これは、新しいInvoke-NativeShell / insコマンドレットを介して強くお勧めします。

私は個人的にInvoke-NativeShellコマンドレットのアイデアが好きですが、いくつかの点で呼び出し演算子--%よりも優れています。 このアイデアについて私が聞いた主な懸念は、 --% + Ctrl + vよりも入力が多く、ここで文字列を補間することと文字列を区別することは、ユーザーにとってもう1つの負担であるということです(_私は個人的にins --% _)よりも入力がはるかに簡単です。

このアイデアについて私が聞いた主な懸念は、 --% + Ctrl + vよりも入力が多く、リテラルのhere-stringとinterpolation here-stringを区別することは、ユーザーにとってもう1つの負担であるということです(_私は個人的にins --% _)よりも入力がはるかに簡単です。

たぶんPSRLが役立つでしょう。 サラウンド貼り付けられたパスにキーハンドラについての問題と同様に、PSRLは読むことができるCommandAst 、それの参照insとが適切に貼り付けた文字列をエスケープします。

それは、この目的のために設計された別のASTタイプを構築するでしょう。 ASTの一部でない場合は、基本的にコメントと同じで、何も起こりません。

もちろんですが、木は些細なものになります。 実行されるコマンドの意味は反映されません。

プロセスcmd.exeリダイレクトstdin / stdioを開始すると、文字列を使用して呼び出すことができます-NativeCommandはbashと同じです

それを聞いてうれしい、@ daxian-dbw。
アイデアが大好きです、

リテラルのhere-stringとinterpolatinghere-stringを区別することは、ユーザーにとってもう1つの負担です。

--%とは異なり、 @"<newline>...<newline>"@使用すると、_PowerShell_変数と式の値をネイティブコマンドラインに直接組み込むことができるため、これは_plus_だと思います。

もちろん、これは、ユーザーが一重引用符(逐語的)と二重引用符(補間)の文字列の違いと、選択的な` - $エスケープについて知っていることを前提としていますが、それは重要だと思います(高度な)オプションがあります。

カットアンドペーストのユーザーを支援するために、提案されたPSReadLine機能はデフォルトで@'<newline>...<newline>'@ (逐語的)になっている必要があります。


最終的には、ユーザーがPowerShellの固有の構文要件を理解する必要がないという考え方を促進したくはありません。代わりに、ユーザーがもたらす追加のパワーに照らして、ユーザーの理解を促進したいと考えています。

ただし、ユーザーがPowerShellの_own_構文(定義上は_cross-platform_)を使用するように促すには、予測どおりに機能する必要があります。
そのためには、#1995を修正する必要があります。理想的には直接

要約する:

  • --% (ここで提案されている新しい演算子形式)のようなものは、定義上、_プラットフォーム固有の_機能であり、#1995の修正に代わるものではありません

  • Invoke-NativeShellins )は、提案された--%演算子のすべての制限を回避し、 @ joeyaielloが言及した「トラップドア」ソリューションを提供します。記述されたコマンドラインを実行する簡単な方法です。ネイティブシェルの場合、PowerShellの構文に適合させる必要はありません。

  • --%は、元の_argument_形式のみのままで、_Windowsのみ_の機能(技術的にはそうではありませんが、効果的に)のままにする必要があります。つまり、変更は必要ありません。

    • #1995が修正されると、 --%の唯一の目的は_Windowsのエッジケース_に対応することです。 msiexecなどの不正なプログラムに渡されるコマンドラインの明示的な引用を制御できるようにします。非常に特殊な形式の引数内引用。

PS v7.xで本当に必要な他の機能の1つは、このRFCで説明されているset -eように、エラーコードで終了するネイティブコマンドにスクリプトを停止させる機能です。 その解決策がInvoke-NativeCommandようなものである場合、それはInvoke-NativeShellと混同されますか?

ネイティブ機能を呼び出すのと同じくらい、msbuild、cl、cmake、Conan、npmなどを呼び出すときにビルドとテストのスクリプトがエラーになり、それらのネイティブコマンドがで終了するため、ムービーを少し前に再生しようとしています。 $ LASTEXITCODEを常にチェックすることを忘れないでください。ゼロ以外の終了コード。 実装が$PSNativeCommandInErrorActionPreference別の設定変数を介して行われる場合、それはネイティブシェルの呼び出しに影響を与えると思います-それはネイティブの「コマンド」であり、すべてですか?

このアイデアについて私が聞いた主な懸念は、 --% + Ctrl + vよりも入力が多く、リテラルのhere-stringとinterpolation here-stringを区別することは、ユーザーにとってもう1つの負担であるということです(_私は個人的にins --% _)よりも入力がはるかに簡単です。

たぶんPSRLが役立つでしょう。 サラウンド貼り付けられたパスにキーハンドラについての問題と同様に、PSRLは読むことができるCommandAst 、それの参照insとが適切に貼り付けた文字列をエスケープします。

しかし、どうですか:

$c = gcm ins
& $c ...

PSRLは、そこで何が起こっているのかを認識するのに苦労するでしょう。 ステートフルである必要があり、エイリアスinsをinvoke-nativeshellに解決してから、commandinfoを呼び出したいと考えてから、引数を削除しますか? 私は本当に、偽のコマンドを特別にケーシングするという考えが本当に嫌いです。

リテラルのhere-stringとinterpolatinghere-stringを区別することは、ユーザーにとってもう1つの負担です。

--%とは異なり、 @"<newline>...<newline>"@使用すると、_PowerShell_変数と式の値をネイティブコマンドラインに直接組み込むことができるため、これは_plus_だと思います。

@ mklement0をフォローしていません。 --%にこれを行うように教えられないのはなぜですか? 私はすでにこれをユースケースとして示しました。

私は本当に、偽のコマンドを特別にケーシングするという考えが本当に嫌いです。

何の偽のコマンドは、唯一の正真正銘のコマンドレット、ここではありませんInvoke-NativeShellの別名、 ins

gcm insGet-Command ins )は、 insエイリアスに関する情報を[System.Management.Automation.AliasInfo]インスタンスの形式で提供します。これは、後で&に渡すことができます。他のコマンドやエイリアスと同様に、呼び出しには

したがって、例は意図したとおりに機能します。 gcmGet-Command )迂回を使用する場合は、適切な文字列リテラル構文_yourself_をスペルアウトする必要があります。 @SeeminglyScienceの提案が実装されている場合PSRLは、提供_could_こと_optional便利なコマンドscaffolding_:

$c = gcm ins
& $c @'
python -c 'print("hi")' | cat -n
'@

または、#13204で提案されている新しい生の文字列リテラル構文が実装されている場合:

$c = gcm ins
& $c @' python -c 'print("hi")' | cat -n '@

もちろん、PowerShellの文字列リテラルの構文に精通している場合は、通常の単一引用符で囲まれた文字列でもかまいません。全体の'...'文字列内に埋め込まれた' 2倍にするだけです。

$c = gcm ins
& $c 'python -c ''print("hi")'' | cat -n'

--%にこれを行うように教えられないのはなぜですか?

  • --%は終了区切り文字がないため、Powershellパイプラインでの使用が妨げられます。これは許容できない制限です( (...)エンクロージャーはオプションではないことに注意してください。これは、すべての出力を事前に収集することを意味するためです。 _streaming_処理ではなくメモリ内の行)。

  • Unixでは、 --%は、PowerShellメタ文字としての$とPOSIXシェルメタ文字としての

繰り返しになりますが、PowerShellに_異なるシェルの構文_をシューホーニングすることには_正当化はなく、メリットもありません-ネイティブシェルのコマンドラインを_文字列として_ insに渡すと、すべての概念上の問題が解消されます。

Invoke-NativeShellは、PowerShellがネイティブシェルではないことを意味します。 その仮定は常に正しく、常に正しいのでしょうか?

ユースケースの@oisingは、誰かがREADMEなどからネイティブコマンドをコピーして貼り付けることです。 ins SPACE CTRL + vと入力するよりも複雑なことをしている場合は、通常のように独自の文字列を作成してエスケープします。

@ mklement0

ただし、ユーザーがPowerShellの_own_構文(定義上は_cross-platform_)を使用するように促すには、予測どおりに機能する必要があります。
そのためには、#1995を修正する必要があります。理想的には直接

これはins / --%の議論とは別ですよね? 同意できない場合は、その問題が新しいコマンド/構文に影響する理由を明確にできますか?

@SeeminglyScience 、はい、それは別ですが、それはこのスレッドでは明確ではありません。
#1995がここに登場した唯一の理由は、元々この問題のために閉鎖されていたため(幸いにもその後再開されました)、ここのOPは、この問題で修正されると述べています(「これでこれらの問題も解決されるはずです:」) 。
したがって、 ins / --%は#1995に対応しないことを強調したいと思います。これには、緊急に独自の修正が必要です。
(PowerShell独自の引数の受け渡しが適切に機能する場合にのみ、良心的に、ユーザーがPowerShell独自の構文を完全に学習して採用することをお勧めします。これは必要です。)

@ SP3269 、私たちはそれに到達したときにその橋を渡ることができます😁。

しかし真剣に:

「ネイティブ」を「ホストプラットフォーム[ファミリ]用に特別に作成された」と考えると、PowerShellが特定のプラットフォームのデフォルトのシステムシェルになる場合でも、名前は適切です(ここでは期待していますが、私は思いません)これは現実的ですが、少なくとも予見可能な将来ではありません)。

代替案について:

  • Invoke-[System]DefaultShellが最も正確な名前です(ただし、PowerShellがシステムのデフォルトシェルになった場合、明確に適用されなくなります)が、PowerShellの世界では「ネイティブ」がより一般的に使用される用語のようです。

  • Invoke-LegacyShellは、Windowsである程度の正当性がありますが、Unixユーザーがその用語にあまり親切に思わないだろうと思います。

ここでみんなの動機、アイデア、問題を追跡しようとして私が経験している完全な混乱を解明し始めていると思います。 私たち(少なくとも@ mklement0と私)は、これを同じ概念上の問題の2つの異なるビューに対する2つの異なるソリューションと見なしているようです。 私が提案したのは、 --%を_parser_へのヒントとして使用して、 &演算子の呼び出しと組み合わせて解析方法を変更すること--%スタンドアロンを使用する必要はありません)。一方、MichaelはinsをPowerShell自体の内部ネイティブコマンドブローカーと引数パーサーを置き換えるドロップインコマンドレットと見なしているようで、代わりに文字列/ここを使用してPowerShellのパーサーを変更しようとはしていません。 -目的のパラメーターをキャプチャするための文字列( --%でも使用できると言っています)。

-%に終了区切り文字がないため、Powershellパイプラインでの使用が妨げられています

この点は全然わかりません。 ins / invoke-nativecommandよりも終了区切り文字が不足しているわけではありません。 LHSから区切るかフィードする必要がある場合は、here-stringsを使用します。それ以外の場合は、単一のステートメントと見なされます。

選択する方法に関係なく、コマンドラインをディスパッチするためにネイティブシェルを選択する必要があるようです。 Windowsでは環境変数COMSPEC (デフォルトは%systemroot%\system32\cmd.exe )を使用し、LinuxではSHELL (デフォルトは/bin/bash )を使用することをお勧めします-シェルが使用しない場合存在しない場合は、 /bin/shをターゲットにする必要があります(ほとんどの場合、これはとにかくbashへのシンボリックリンクです)。

-%に終了区切り文字がないため、Powershellパイプラインでの使用が妨げられています

この点は全然わかりません。 ins / invoke-nativecommandよりも終了区切り文字が不足しているわけではありません。 LHSから区切るかフィードする必要がある場合は、here-stringsを使用します。それ以外の場合は、単一のステートメントと見なされます。

基本的に、 cmd --% /c someapp | someOtherAppようなものを呼び出して、cmdにパイプラインを処理させることはできません。 PowerShellは、パイプライン(および、Unixユーザーに役立つ&&||などの他のいくつかのもの)を、の一部としてネイティブコマンドに渡すのではなく、PowerShellトークンとして解釈します。引数文字列。

LinuxではSHELL(デフォルトは/bin/bash

いいえ: Unixライクなプラットフォームの_system_シェルは_常に_ /bin/shです。
これは、特定の_user's_インタラクティブシェル( $env:SHELL反映されます-ただし、残念ながら、現在_PowerShell_がユーザーのシェルである場合はそうではありません。#12150を参照)とは異なります。これは、(a)構成可能であり、(b)多くの場合_defaults to_ /bin/bashですが、macOSが最近新しいユーザーのデフォルトのインタラクティブシェルとして/bin/zsh移行したことからもわかるように、それでも指定されていません。

Windowsでは環境変数COMSPECを使用することをお勧めします

良い点は、Windowsでシステムシェル(コマンドインタープリター)を参照するためのより良い方法です-それに応じて上記のサンプルコマンドを更新しました。

PS v7.xで本当に必要な他の機能の1つは、このRFCで説明されているset -eように、エラーコードで終了するネイティブコマンドにスクリプトを停止させる機能です。 その解決策がInvoke-NativeCommandようなものである場合、それはInvoke-NativeShellと混同されますか?

ネイティブ機能を呼び出すのと同じくらい、msbuild、cl、cmake、Conan、npmなどを呼び出すときにビルドとテストのスクリプトがエラーになり、それらのネイティブコマンドがで終了するため、ムービーを少し前に再生しようとしています。 $ LASTEXITCODEを常にチェックすることを忘れないでください。ゼロ以外の終了コード。 実装が$PSNativeCommandInErrorActionPreference別の設定変数を介して行われる場合、それはネイティブシェルの呼び出しに影響を与えると思います-それはネイティブの「コマンド」であり、すべてですか?

その目的のために、 buildモジュールにStart-NativeExecutionがあります。

私はそれを見ました。 後でゼロ以外の終了コードを効果的にスローしたい場合、 Start-NativeExecutionInvoke-NativeShellどの程度正確に組み合わせるでしょうか。 PR#3523のようなものが、この呼び出しネイティブ機能と一緒に機能することを本当に望んでいます。2つを連携させたいからです。 呼び出しネイティブがコマンドレットとして実装されることになった場合(Invoke-NativeShell vs-%)、 -ErrorAction Stopを実装して、ゼロ以外の終了コードでスロー(終了エラー)させることができると思います。

-%に終了区切り文字がないため、Powershellパイプラインでの使用が妨げられています

この点は全然わかりません。 ins / invoke-nativecommandよりも終了区切り文字が不足しているわけではありません。 LHSから区切るかフィードする必要がある場合は、here-stringsを使用します。それ以外の場合は、単一のステートメントと見なされます。

基本的に、 cmd --% /c someapp | someOtherAppようなものを呼び出して、cmdにパイプラインを処理させることはできません。 PowerShellは、パイプライン(および、Unixユーザーに役立つ&&||などの他のいくつかのもの)を、の一部としてネイティブコマンドに渡すのではなく、PowerShellトークンとして解釈します。引数文字列。

はい、現在の動作@ vexx32を理解しています。 しかし、私たちは(少なくとも私は) --%現在の振る舞いについて話していません-私たちはそれを強化することについて話しているのですよね? ここでみんなが話し合っているような気がするのはなぜですか? :)

私は道、道まで以上述べたように、我々は高めることができる&して仕事に--%これが可能であるようにします。 また、引数を使用したシェルの暗黙的なネイティブexecと明示的な呼び出しについて明確にする必要があると思います。 これは、経験豊富なWindowsユーザーであっても、他の実行可能ファイルを「実行」するためにcmd.exe(シェル)が必要であるという混乱の原因です。 同じことがlinux / osxにも当てはまります。

はい、私は_current_の動作@ vexx32を理解しています。 しかし、私たちは--%の_現在の_動作について話しているのではありません(少なくとも私は話していません)-それを強化することについて話しているのですよね? ここでみんなが話し合っているような気がするのはなぜですか? :)

したがって、 --%を調整するための現在の提案は、コマンド名が通常ある場所である場合、その右側のすべてがそのまま(改行まで)解析さ、bash / cmdに直接送信されるというものです。 ヒア文字列のようなPowerShell構文の余地はありません。それは、 --%とネイティブコマンドプロセッサが現在抱えているのと同じ問題をすべて抱えているからです。

私はそれを見ました。 後でゼロ以外の終了コードを効果的にスローしたい場合、 Start-NativeExecutionInvoke-NativeShellどの程度正確に組み合わせるでしょうか。 PR#3523のようなものが、この呼び出しネイティブ機能と一緒に機能することを本当に望んでいます。2つを連携させたいからです。 呼び出しネイティブがコマンドレットとして実装されることになった場合(Invoke-NativeShell vs-%)、 -ErrorAction Stopを実装して、ゼロ以外の終了コードでスロー(終了エラー)させることができると思います。

現在はStart-NativeExecution { Invoke-NativeShell <strong i="10">@whatever</strong> }ます。

この点は全然わかりません。 ins / invoke-nativecommandよりも終了区切り文字が不足しているわけではありません。 LHSから区切るかフィードする必要がある場合は、here-stringsを使用します。それ以外の場合は、単一のステートメントと見なされます。

Invoke-NativeShellは通常のコマンドであるため、終了区切り文字は必要ありませんが、 --%の恐怖は必要ありません。

LinuxではSHELL(デフォルトは/bin/bash

いいえ: Unixライクなプラットフォームの_system_シェルは_常に_ /bin/shです。

実行可能なスクリプトファイルを作成して実行するのと同じことだと思います。これにより、適切なシェルを選択するタスクがオペレーティングシステムに委任され、煩わされることはありません。 含めて、それが#!で始まる場合

Invoke-NativeShell背後にある考え方は、ネイティブシェルの_CLI_の周りに便利なラッパーを提供することです。

  • Unixでは、これで十分であり、補助スクリプトファイルを作成すると、余分なオーバーヘッドが発生するだけでなく、 $0 (スクリプトファイルパス)でランダムな値が報告されますが、CLIを介した呼び出しには、予想どおり/bin/shが含まれます。 sh -c 'echo $0' foo )を付けて明示的に設定することもできます。

    • (余談ですが、シバン行#!/bin/shを使用してシェルスクリプトを作成するということは、 /bin/sh直接呼び出すのと同じように、フルパスでシステムシェルをターゲットにすることを意味します)。
  • Windowsでは、バッチファイルを介した実行は、 %エスケープの問題を回避するため、利点をもたらします(ただし、 $env:ComSpec予想どおりに行うシステムシェルの場所を特定するタスクを委任する場合はそうではありません)。そしてfor言及した行動の上

後者を礼儀として(ユーザーが独自の補助バッチファイルを作成する必要がないように)対処するために、概念を明確にするために、
-AsBatchFileスイッチを_opt-in_として。

とはいえ、カットアンドペーストに使用されるパブリックcmdコマンドラインの大部分が_batch-file_セマンティクスを念頭に置いて記述されているというコンセンサスがある場合( %iではなく%%iループ変数としての%i 、逐語的な%%%としてエスケープする機能)、おそらく常にauxを使用します。 Windows上のバッチファイル(Unix上のCLIを使用している間)がより良い解決策です-私はこれについて強くは感じませんが、特に他のスクリプト言語とは異なる動作を示すことを意味することを考えると、明確に文書化する必要があります。

@rkeithhill

私にとって、リンク先のネイティブエラー

どちらも、PowerShellで外部プログラム(ネイティブユーティリティ)を第一級市民にするために必要な手順を表しています(概念的に可能な限り)。

第一級市民であるということは、コマンドレットを介してではなく、_直接_呼び出し(状況に応じて_構文上の理由でのみ&必要)を意味します。
言い換えると、 Invoke-NativeCommandコマンドレットまたはStart-NativeExecutionコマンドレットがあってはなりません。

(余談ですが、 buildモジュール内の多くの関数がそうであるため、 Start-NativeExecution名前が間違っています。 Start _非同期_操作を通知しますが、これらの関数のほとんどは_同期_です-についての説明を参照してください。 Start-Sleep (https://github.com/MicrosoftDocs/PowerShell-Docs/issues/4474)。

したがって、 Invoke-NativeShellは特別な考慮を必要としません。PowerShellは、すでに行っているように、ネイティブシェル実行可能プロセス( cmd / shによって報告された終了コードに基づいて$LASTEXITCODEを設定します。 sh )が呼び出されました。

次に、RFCで提案されているメカニズムは、直接呼び出された実行可能ファイルに作用するので、それに作用します(たとえば、 $PSNativeCommandErrorAction = 'Stop'が設定されている場合、 $LASTEXITCODEがゼロ以外の場合、スクリプト終了エラーが発生します。 )

(簡単に言うと、この議論はここには属していません:_per-call_メカニズムについて:次のようなもの
/bin/ls nosuch || $(throw 'ls failed)は、 /bin/ls nosuch || $(exit $LASTEXITCODE) (POSIXシェルの/bin/ls nosuch || exitと同等)と同様に機能します。 #10967は、残念ながら$(...)回避できない理由を説明しています(文法を大幅に変更しない限り)。 同様に、 $LASTEXITCODE明示的に参照する必要があることは、おそらく避けられません。)

(余談ですが、シバン行#!/bin/shを使用してシェルスクリプトを作成するということは、 /bin/sh直接呼び出すのと同じように、フルパスでシステムシェルをターゲットにすることを意味します)。

それは私が言いたかったことではありません。 オペレーティングシステムにはこの機能が組み込まれているため、PowerShellはデフォルトのシェルが何であるかを知る必要はありません。Linuxは、 #!で始まらない場合、またはで始まる場合に実行可能スクリプトを実行する方法を知っています。 #!/usr/bin/env pythonような他の何か、そしてWindowsは.CMDスクリプトを呼び出すために何をすべきかを知っているので、私たちも%COMSPEC% 'n'のものを覗いてはいけません。 Windowsは他のスクリプトも実行できますが、スクリプトファイルの拡張子に基づいているため、この場合には明らかに当てはまりません。

繰り返しになりますが、 Invoke-NativeShellのマンデートは、ネイティブシェルの_CLI_を呼び出す必要があり、バックグラウンドで補助スクリプトファイル(副作用あり)を作成するのではありません(上記のさまざまな理由を除く)。

システムシェルを確実に決定することに関しては、ここで解決する問題はありません。Windowsで$env:ComSpec/bin/shをハードコーディングすることは完全に適切です。

いいえ、システムコールレベルのUnixプラットフォームは、実行可能なプレーンテキストファイルを_シバン行なしで_実行する方法を_知りません_。 そのようなファイルをまだ_できる_ことは、POSIXのようなシェルの便利な機能です。それらはexecを試し、次にそのようなファイルを_それらのために_書かれたものとして解釈するために_フォールバック_します。 つまり、実行されているPOSIXのようなシェルがファイルを実行することになりますが、PowerShellはこの礼儀フォールバックを実装していないため、単に_失敗_します( Program 'foo' failed to run: Exec format error取得します)。

したがって、言うまでもなく、このようなスクリプトを作成することはお勧めできません。

いいえ、システムコールレベルのUnixプラットフォームは、実行可能なプレーンテキストファイルを_シバン行なしで_実行する方法を_知りません_。 そのようなファイルをまだ_できる_ことは、POSIXのようなシェルの便利な機能です。それらはexecを試し、次にそのようなファイルを_それらのために_書かれたものとして解釈するために_フォールバック_します。 つまり、実行されているPOSIXのようなシェルがファイルを実行することになりますが、PowerShellはこの礼儀フォールバックを実装していないため、単に_失敗_します( Program 'foo' failed to run: Exec format error取得します)。

cshはPOSIXに似ておらず、裸のスクリプトでexec失敗することはありません。 sh呼び出します。 perlです。

これが私の主張を明確にしていることを願っています。何をすべきかを決めるのは_各シェル次第_であり、異なるシェル/スクリプト言語は異なることを行います。 PowerShellは現在、失敗しているだけです。選択を行う必要があり、その選択を/bin/shにしたい場合は、最初の段階に戻ります。 /bin/sh想定する必要があります。

これが私の主張を明確にしていることを願っています。何をすべきかを決めるのは_各シェル次第_であり、異なるシェル/スクリプト言語は異なることを行います。 PowerShellは現在、失敗しているだけです。選択を行う必要があり、その選択を/bin/shにしたい場合は、最初の段階に戻ります。 /bin/sh想定する必要があります。

execperlダイレクトシステムコールがあり、 perlどのような方法でそれを変更しません。 特に、インタプリタを_選択_しません。

もちろん、これは、ユーザーが一重引用符(逐語的)と二重引用符(補間)の文字列の違いと、選択的な` - $エスケープについて知っていることを前提としていますが、それは重要だと思います(高度な)オプションがあります。

多分それは私だけですが、私は千の"を1つの-fと交換します。

@ yecril71pl

perlのexecは直接のシステムコールであり、perlはそれを変更しません。 特に、通訳を選びません。

#!行のないスクリプトで動作する場合、これは当てはまりません。 Linuxでのexecsyscallは、簡単にテストできるため、 #!なしでは機能しません。

user@Programming-PC:/tmp/exec_test$ ls
test.c  testscript
user@Programming-PC:/tmp/exec_test$ cat test.c
#include <unistd.h>
#include <stdio.h>

int main(int argc, char **argv) {
  char *binaryPath = "./testscript";

  execl(binaryPath, binaryPath, NULL);

  perror("Error");

  return 0;
}
user@Programming-PC:/tmp/exec_test$ gcc test.c -o testexecutable
user@Programming-PC:/tmp/exec_test$ chmod +x testscript 
user@Programming-PC:/tmp/exec_test$ cat testscript 
echo test from script
user@Programming-PC:/tmp/exec_test$ #works from shell:
user@Programming-PC:/tmp/exec_test$ ./testscript 
test from script
user@Programming-PC:/tmp/exec_test$ #doesn't work via exec syscall:
user@Programming-PC:/tmp/exec_test$ ./testexecutable 
Error: Exec format error
user@Programming-PC:/tmp/exec_test$ vim testscript 
user@Programming-PC:/tmp/exec_test$ cat testscript 
#!/bin/sh
echo test from script
user@Programming-PC:/tmp/exec_test$ #exec syscall works with #! line:
user@Programming-PC:/tmp/exec_test$ ./testexecutable 
test from script
user@Programming-PC:/tmp/exec_test$ uname -a
Linux Programming-PC 4.4.0-176-generic #206-Ubuntu SMP Fri Feb 28 05:02:04 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
user@Programming-PC:/tmp/exec_test$ 

編集:ライブラリ関数execlpを使用すると、manページによると次のことに気づきました。

ファイルのヘッダーが認識されない場合(試行されたexecve(2)がエラーENOEXECで失敗した場合)、これらの関数は、ファイルのパスを最初の引数としてシェル(/ bin / sh)を実行します。 (この試行が失敗した場合、それ以上の検索は行われません。)

ただし、これは「linux」の機能ではなく、gnu cライブラリの機能です。また、manページによると、ユーザー定義可能なシェルではなく、明示的に/ bin / shを使用しています。 ( posix/execvpe.cnew_argv[0] = (char *) _PATH_BSHELL; )およびsysdeps / unix / sysv / linux / paths.h (またはsysdeps / generic /paths.hのソースにハードコードされています-どのヘッダー#define _PATH_BSHELL "/bin/sh" ))

ただし、これは「linux」の機能ではなく、gnu cライブラリの機能です。また、manページによると、ユーザー定義可能なシェルではなく、明示的に/ bin / shを使用しています。 ( posix/execvpe.cnew_argv[0] = (char *) _PATH_BSHELL; )およびsysdeps / unix / sysv / linux / paths.h (またはsysdeps / generic /paths.hのソースにハードコードされています-どのヘッダー#define _PATH_BSHELL "/bin/sh" ))

sysdeps/**/linuxから来ているので、Linuxのものです。 これも一般的なものかもしれませんが、オーバーライド可能です—明らかにローカルではなく、OSごとです。

はい、私は_current_の動作@ vexx32を理解しています。 しかし、私たちは--%の_現在の_動作について話しているのではありません(少なくとも私は話していません)-それを強化することについて話しているのですよね? ここでみんなが話し合っているような気がするのはなぜですか? :)

したがって、 --%を調整するための現在の提案は、コマンド名が通常ある場所である場合、その右側のすべてがそのまま(新しい行まで)解析され、bash / cmdに直接送信されるというものです。 ヒア文字列のようなPowerShell構文の余地はありません。それは、 --%とネイティブコマンドプロセッサが現在抱えているのと同じ問題をすべて抱えているからです。

ああ、ロードリー...みんなが私を荒らそうとしているだけですか? 😄いいえ、Patrick-PowerShell式を使用する場合は、ここで使用します- --%文字列。 複数行が必要な場合は、here-stringsを使用してください。 変数置換なしのマルチラインが必要な場合は、一重引用符のヒア文字列を使用できます。

とにかく、私はこのゲームにスキンを持っていません、そして私は十分に言ったと思います。 コマンドレットを使用してシェル内から別のシェルに延期することには、まだ深刻な問題があると思います。 不器用です。 コマンドレットを使用して別のシェルを実行し、そもそもそのセカンダリシェルを必要としないネイティブコマンドを実行する場合は、特に扱いにくいです。 全体が悪臭を放ちます。

編集:最後の言葉

このアイテムのタイトルは「ネイティブオペレーターを呼び出す」です。 呼び出し演算子&すでにあり、ネイティブコマンドへの引数の受け渡しを処理するように設計されたトークン--%すでにある場合、無駄な機会があります。 現在、 &--%は認識されていないため、このシナリオを有効にして、ここで説明している問題を修正するための特定の動作を与えることにした場合、重大な変更は発生しません。

PowerShell式を使用する場合は、ここで使用します- --%文字列。 複数行が必要な場合は、here-stringsを使用してください。

演算子のポイントは、PowerShell構文を文字通り解析しないことです。 ヒア文字列のようなものはありません。 一重引用符で囲まれた文字列定数のようなものはありません。 「式を右に評価し、文字列に変換してその値を送信する」ではなく、「テキストをそのまま右に送信する」です。

したがって、たとえば、これがある場合:

--% @'
echo my native command
'@

それは次のように翻訳されます:

cmd.exe /c "@'"
echo my native command
'@

'@は、 @を含む単一引用符で囲まれた文字列定数の始まりにすぎないため、パーサーエラーが発生する場合を除きます。

insのピッチとほぼ同じになるように、実装を別の方法で描いていると思いますが、上記は--%で議論されている現在のピッチです。

また、これが既存の機能の仕組みでもあることにも注意してください。 この例はほとんど同じように機能します。

cmd /c --% @'
echo my native command
'@

私は繰り返します:

現在、&with-%の使用は認識/未定義ではないため、このシナリオを有効にして、ここで説明している問題を修正するための特定の動作を与えることにした場合でも、重大な変更は発生しません。

さらに明確に説明しましょう: &と一緒に使用する場合、ヒア文字列が--%に続くようにします

ああ、それは大きな問題です-ええ、私はそれを逃しました、ごめんなさい@oising。

そのアイデアについて、 --% 、あるコンテキストでは解析を停止し、他のコンテキストでは「ネイティブ引数バインディングでより良い仕事をする」ことを意味するのは少し混乱すると思います(同様にInvoke-NativeShellように機能させることで)代わりにそれが意味する場合は

exec 、@ TSlivedeを深く掘り下げてくれてありがとう。 要約して、うまくいけばこの接線を閉じてみましょう。 LinuxとmacOSの両方に適用されます。

Unixにはexecと呼ばれるシステム(またはライブラリ)関数はありません。名前にexecれる関連関数の_family_のみがあります(ほとんどの関数はプレフィックスとして使用されます)。

  • _system_関数( manセクション2 )、その中心にあるexecve 、シバンのないスクリプトを実行しようとすると_fail_。

  • システム関数上に_構築する_library_関数( manセクション3 - man 3 exec )のうち、 p (「パス」の場合)を持つ関数のみ推定)システムシェルへのパスフォールバックがあります(例: execlp )。

    • @TSlivedeが示しているように、これらの関数のGNUライブラリ実装は/bin/shハードコーディングしますが、BSDベースの実装shを使用し、 shに依存します。 $env:PATH (ただし、不思議なことに、 manページには/bin/sh )。

前述のように、_直接実行_の場合、主要なPOSIXのようなシェル( bashdashksh 、およびzsh )は、シバンのないスクリプトの実行にフォールバックします。 _themselves_は、 execライブラリ関数間でフォールバックバリアントを使用しないことを意味します。 対照的に、独自のexec関数に対するperlの選択は、フォールバックに依存することでした。 同様に、主要なPOSIXのようなシェルのexec _builtins_は、 bashを除いて、フォールバックに依存しています。

Unixでは、舞台裏でスクリプトファイルを使用する必要がないため、システムシェルパスについてフォールバックライブラリ関数と同じ仮定を立てることができます。 shよりも

shの場所を義務付けていない

  • /bin/shは、デファクトスタンダードの場所であるため、特に、シバン行が_full、literal_のみをサポートしていることを考えると、フルパスでshを参照するポータブルUnixシェルを作成する必要があるためです。パス( #!/bin/sh )。

  • 逆に、 $env:PATHを操作して別のshを呼び出すことができる場合、 $env:PATH shを介してsh 、セキュリティリスクになる可能性があります。

同じリスクが位置決めに適用cmd.exeを介して、 $env:ComSpecので、おそらくより良い方法を呼び出すことで、方法により、 GetSystemDirectory WinAPIの関数と追記\cmd.exeにその結果( $env:ComSpecが定義されていない場合

/bin/shは、デファクトスタンダードの場所であるため、特に、シバン行が_full、literal_のみをサポートしていることを考えると、フルパスでshを参照するポータブルUnixシェルを作成する必要があるためです。パス( #!/bin/sh )。

通常、 #!/usr/bin/env shと言います(システムスクリプトを除く)。

  • 通常、あなたは_しない_: 「#!/ bin / sh」をグーグルすると約3,900,000の一致が得られ、 「#!/ usr / bin / envsh

  • 通常、あなたは_すべきではありません_: $env:PATH最初に来るshユーティリティではなく、_the_システムシェル/bin/shを予測どおりにターゲットにします。

shという名前の実行可能ファイルをターゲットにする唯一の理由は、最小公分母-仮定-POSIX-features-only _system_シェル、つまり/bin/shを移植可能にターゲットにすることです。

通常、あなたは_しない_: 「#!/ bin / sh」をグーグルすると約3,900,000の一致が得られ、 「#!/ usr / bin / envsh

Web検索をユーザースクリプトに制限する方法はありません。特に、多くのユーザースクリプトは実行可能としてマークされていないため、実行可能としてマークされている場合でも、 execlp依存している可能性があります。 しかし、ほとんどのユーザースクリプトがそう言ったとしても、_normal_を_customary_と見なすべきではありません。 PowerShellによって実行されるスクリプトは、ユーザースクリプトです。 ユーザーがシェルを必要とするとき、彼らは妄想的でない限り、 /bin/shではなくshを呼び出します。

@oising

ネイティブシェルコマンドラインを_単一の文字列として_(最も簡単な文字列(-literal)形式で)渡し、_only_を単一の文字列として渡します(Unixでサポートされている追加のコマンドラインへのパス引数を保存します(のみ)上記で説明)-あなたがそれに同意すると仮定すると-共通点のように聞こえます。

コマンドラインを_単一の文字列_として渡すことは、次の前提条件です。

  • このような呼び出しを_PowerShell_パイプラインに組み込むことができます。
  • _PowerShell変数と式_をネイティブシェルコマンドラインに組み込むことができます。

単一の文字列を渡すことは、呼び出しが行うことの_直接的な概念表現_です。 対照的に、_individual_(オプションでベアワード)引数を使用して、PowerShellに別のシェルの構文を直接組み込むことを試みると、解決できない問題が発生し、既存の--%すでに具体化している基本的な制限との混乱を招きます。


その場合、その単一文字列コマンドラインを渡すために_operator_または_cmdlet_を選択するかどうかはそれほど重要ではないと主張することもできますが(_discoverability_の質問を除いて)、両方の&使用について概念的な懸念があります。 --% (前に& ):

  • &に関する懸念:コマンドラインを含む-quoted-文字列を渡す必要がある場合、効果的に_expression_モードで動作していますが、 &現在_argument_モードを意味します(つまり、次のことを意味します)。 _individual_引数、必要な場合にのみ引用)。 したがって、 &の関与は混乱を招きます。

  • --%に関する懸念は、Windowsのみの起源と、解析停止記号としての--%混乱したセマンティクスに関するものです。 ストップ解析シンボルとしての--%が_argument_モードで動作する場合
    & /bin/ls --% dir1 dir2 )、 & --%は_expression_モードで動作します(例: & --% '/bin/ls dir1 dir2 >out.txt'


一歩下がって、現在実装されている停止解析記号である--%を調べてみましょう。

これは、2つの最終的に無関係な問題を解決する試みでした(当時はWindowsのみ)。

  • (a)他のプラットフォームにも適用されるユースケース: cmd.exe /ネイティブシェル用に記述された_コマンドライン_をそのまま再利用できるので、PowerShellの構文に適合させる必要はありません。

  • (b)常にWindowsのみの問題:PowerShellの一般的な舞台裏の再引用では提供できない非常に特殊なスタイルの引用を必要とする_rogue CLI_(つまり、_single_外部コンソールアプリケーションの呼び出し)を呼び出します。 、そのようなCLIのWinAPIに最終的に渡されるコマンドラインを作成できるようにすることで_verbatim_。 (問題の説明をこれに限定することは、PowerShellの再引用が一般的に適切に機能することを前提としていますが、これは決してありません-これは#1995の主題です)。

--%は、(a)と(b)の両方に対する解決策の混乱した_conflation_として実装され、どちらの問題も適切に解決しませんでした。

  • これは(a)の解決策として宣伝されましたが、実際には厳しい制限があります。これは、_エミュレートする唯一のcmd exe機能は、 %...%スタイルの環境変数参照の拡張であるためです_:

    • |前提cmd 、_single_
      &&|| 、その時点では実装されていませんでしたが、 cmdのパス部分を暗黙的に終了します。

    • _single_ & -これはcmdのマルチコマンドセパレーターです-_は通過しますが、それもマルチコマンドのサポートにはなりませんでした。なぜなら- cmdないからです。実際に関与している- &は_逐語的にターゲットプログラムに渡されます_; 例えば
      echoArgs.exe --% a & baエコーせず、 b呼び出し、逐語的な引数a& 、およびb渡します。 echoArgs

    • 引用符で囲まれていない引数のcmdのエスケープ文字( ^ )は使用されません。

    • 当然の結果として、既存の環境変数を参照する%...%トークンは_常に_展開されます。 ^を介してそれを防ぐ試みは正しく機能しません(例:
      echoArgs.exe Don't expand %^USERNAME%は、 cmd展開を防ぎ、 ^ _を取り除き、PowerShellからechoArgs.exe --% Don't expand %^USERNAME%として呼び出されたときに^保持します。

  • (b)の解決策として、それも不十分でした。

    • (a)の使用と同様に、最初に_auxを不自然に定義する場合を除いて、_PowerShell_変数と式をコマンドに組み込むことはできません。 次に、 --%後に%...%を介して参照するenvironment_variable_; 例えば
      $env:FOO='foo'; echoArgs.exe --% %FOO%!

ここで説明するように、(a)の適切な解決策はInvoke-NativeShell / insた。

(b)の適切な解決策は、次のとおりです。

  • _first_引数と同じくらい特別な--%をサポートする
  • また、 ins場合と同様に、パススルーコマンドラインを構成する_単一の文字列_が続く必要があります_全体として_また、文字列補間(または文字列を作成する他の方法)
  • たとえば、 msiexec --% "/i installer.msi INSTALLLOCATION=`"$loc`""$loc 'c:\foo\bar none'が含まれていると、逐語的なコマンドライン/i installer.msi INSTALLLOCATION="c:\foo\bar none"が通過し、 msiexecの非標準要件を満たします。 <prop>=<value>引数では、 <value>部分のみが二重引用符で囲まれます。

それは_便利_ではありませんが、Windowsで渡されるコマンドラインベースの引数である無政府時代への堅牢なソリューションに支払う代償です。

@ mklement0 (いつものように)患者と思慮深い返事をありがとう。

ですから、私は心から同意します。

(b)の適切な解決策は、次のとおりです。

  • サポート-%最初の引数と同じくらい特別
  • また、insの場合と同様に、パススルーコマンドライン全体を構成する単一の文字列が後に続く必要があります。>-文字列補間(または他の方法)によってPowerShell変数と式を組み込むことができます。文字列の作成)

    • 例:msiexec-% "/ i Installer.msi INSTALLLOCATION = "$loc " "、$ locに 'c:foobar none'が含まれていると、逐語的なコマンドライン/ i Installer.msi INSTALLLOCATION =" c:foobarなし」が通過し、msiexecの非標準要件を満たします。=引数のみ一部は二重引用符で囲みます。

これは、(a)が解決すべき独立した問題として存在する必要があることをまだ実際に理解していないことを除いて、(a)と(b)の両方の一般化された解決策として説明しようとしてきたものです。 私が本当に苦労しているのは、(b)が&に対して_具体的に_実装されている場合、なぜそれが(a)もカバーできないのですか? たとえば、 ins ...は、 & cmd --% ...ができないことを何に与えますか? そして、 &が引数として--%を渡さないことを除けば、重大な変更にはなりません(これはばかげてありそうもないようです)。comspec、shellsについて心配する必要がないというボーナスまたは何でも。 発信者に決定させます。

@ PowerShell / powershell-委員会はこれをレビューしました:

  • これは、実際の使用状況のフィードバックを得るための実験的な機能になります。 私たちはまだ実際の印章を受け入れています。 /bin/sh/bin/env shをPRレビューに延期します
  • ユーザーがコマンドラインを切り取ってPowerShellに貼り付ける「stackoverflow」シナリオ専用の新しい演算子として--%を使用して進めます(もちろん、その前に新しい演算子を使用します)。 )
  • Invoke-NativeShellコマンドレットはこの提案とは別のものであり、PowerShellGalleryのコミュニティによって公開される可能性があります。 また、here-stringを要求しても、それをhere-stringとしてラップすることを事前に知らなければ、ユーザーエクスペリエンスの問題は解決されません。
  • 既存のユーザーがその動作に依存する可能性がある--%スイッチに重大な変更を加えたくありません
  • --%スイッチのようなストリーミング動作が必要なユーザーは、引き続きそのスイッチを使用し、必要に応じて特殊文字をエスケープする必要があります
  • ユーザーが--% (または任意の解決策)について知っておくべき発見の問題がまだあります
  • 現在、PSReadLineを変更して、貼り付けたコンテンツを、ユーザーの意図を予測しようとするここの文字列として変更することはできません。
  • ここで文字列と非ここで文字列(拡張)のシナリオを可能にする複数のソリューションは検討していません。 例: & --% vs --%

また、@ SteveL-MSFTと、これを開くと同時に#1995を閉じたにもかかわらず、これをその問題の決定的な解決策として伝えることは、私たちの意図ではありませんでした。

この特定の機能の利点は、#1995の影響よりもはるかに重要であると私は考えています。 人々がカット/ペーストしたい非PSエンライテンドツール(私自身を含む)のStackOverflowの例とドキュメントの例がたくさんあると思います。

さらに、PowerShellの独自の言語内で適切なエスケープを提供したいという要望もありますが、人々が大勢で#1995にヒットすることはありません(ただし、これについてはここで詳しく説明します)。

  • 新しい演算子として--%前進します

これをドラッグして申し訳ありません。追加のディスカッションは探していませんが、どのような演算子ですか? (私は主に構文に興味があります。)

$a = --% find . -iname *$pdf -print0 | xargs -0 ls -ltr

誰がパイプを手に入れますか? $どうなりますか? &&& 、および||と同様です。

もしあれば、どのような条件下で--%前進するPSパイプで使用できますか?

ありがとう。

これをドラッグして申し訳ありません。追加のディスカッションは探していませんが、どのような演算子ですか? (私は主に構文に興味があります。)

ASTに関しては、技術的にはオペレーターではないかもしれませんが、独自のASTタイプです。 演算子として実装された場合、単項演算子になります。

$a = --% find . -iname *$pdf -print0 | xargs -0 ls -ltr

誰がパイプを手に入れますか? $どうなりますか? &&& 、および||と同様です。

文字列find . -iname *$pdf -print0 | xargs -0 ls -ltrは、そのままネイティブシェルに送信されます。 ただし、 $aは引き続き入力されるため、次の行でそれを何かにパイプすることができます。

もしあれば、どのような条件下で--%前進するPSパイプで使用できますか?

〜最初のコマンド要素スロット〜がステートメントの先頭にある場合、おそらくそうではありません。 これは、新しい構文の魅力の1つです。 開始時に〜最初のスロット〜にない場合は、今日と同じように機能し続けます。

(@ daxian-dbw @ SteveL-MSFTいずれかが間違っている場合は、訂正してください❤️)

@SeeminglyScienceは正確に正しい

最初のコマンド要素スロットにある場合、おそらくそうではありません。 これは、新しい構文の魅力の1つです。 最初のスロットにない場合は、今日と同じように機能し続けます。

アップストリームコマンドの出力を、 --%によって呼び出されるネイティブコマンドに渡すのは難しい場合があります。 --%基本的に、文字列をbashようにネイティブシェルに渡すだけですが、アップストリームコマンドからの出力をbashに送るだけでなく、 findなどのネイティブコマンド自体。

主に「StackOverflow」シナリオ用であるため、ストリーミング動作はこの機能の考慮事項ではないと思います。 したがって、 --%を特別なステートメントastにして、_PowerShell_パイプラインで機能しないことを明確にしたほうがよいと思います。

ああ、「コマンド要素スロット」が間違っている理由があることを私は知っていました。 私は声明の冒頭で意味しました。 直します、ありがとう!

アップストリームコマンドからの出力をbash送ることはできません

_upstream_は_us_を意味しますか? 私はできると思います: 'ls' | bash 。 特別に賢いことではありませんが、可能です。

これについて@jpsnoverと話し合っていたシジルとしてシェバン#!を提案しました。 この場合、次のように入力するだけです。

#!/bin/sh ls | grep foo
#!sh | grep foo

(2番目のケースでは、 shがパスにあると想定しています)。 この場合、シェルを指定する必要があるかどうか、または常にデフォルトシェルで実行するかどうかを決定する必要があるため、この例では、 shが2回開始されます。 ただし、今日のシバンファイルの動作により、これには問題があります。 shebangはコメントとして無視されるため、PowerShellで機能します。 コメントの場合、スクリプトの最初の行を無視することにした場合でも、インタラクティブシェルで問題が発生し、新しい行の各セットが新しいスクリプトであり、そのスクリプトがスクリプトとして実行されているかどうかを判断する方法がありません。スクリプトまたはインタラクティブに。

別の方法は、マークダウン構文を借用することです。

powershell ```bash ls | grep foo ```

この例では、マークダウンコードフェンシング構文を使用します。 これはまた、複数行の問題を解決し、まったく新しいものではない概念を使用します。 新規ユーザーの初期発見の問題がまだあることを考えると、これは、後続のトリプルバックティックが必要であるという点でそれほど悪いことではないと思います。

この場合、これは潜在的に機能する可能性があります。

powershell $a = ```bash ls | grep foo ``` | select-string bar

@ SteveL-MSFTマークダウン構文は非常に理にかなっています。 指定できれば。 Pythonやおそらく拡張機能などの他のタイプもありますか?

シェバン#! 既存のコメントに干渉します。

これは、解析の処理とユーザーが実際に_使用_するための両方で、私には非常に複雑に思えます。

そして、ええ、コメントとして出てこないコメントであるはずの行で人々を混乱させる必要はありません。 #Requiresはすでに一種の奇妙なことに取り組んでおり、シバンがいっぱいになると、せいぜいWindowsの人々、そしておそらくLinuxの人々も混乱するでしょう。

私は個人的にこの機能をシバンと混ぜたくないと思います、それは私の意見では混乱しています。
また、マークダウンコードブロック構文の使用を開始した場合、PowerShellで任意の言語コードを直接実行するように要求するのは時間の問題です。 私たちはそのように行きたいとは思わない...

また、マークダウンコードブロック構文の使用を開始した場合、PowerShellで任意の言語コードを直接実行するように要求するのは時間の問題です。

悪い考えだとわかっていても、文字通りインラインC#の要求を止めることはありません。

埋め込みスクリプトは子プロセスで実行されるため、マークダウン構文は任意の言語コードを導入しません。 @'内に任意の言語コードを配置でき、悪いことは何も起こりません。

チームディスカッションやJeffreyとの話し合いでは、PowerShellスクリプト内で他の言語を実行したい人に反対するべきではありません。 @ yecril71plが指摘したように、私たちは他の言語を直接サポートしていませんが、そのコードを解釈して実行するために別のプロセスに依存しています。 ここでのシナリオは、ユーザーがpythonまたはbashスクリプトのブロックを見て、PowerShellスクリプト内でそのまま使用したいというものです。 人々がこれをすることを要求するものは何もありません。 必要に応じて、他のスクリプトをPowerShellに移植することもできます。 これは、ユーザーがPowerShellにカットアンドペーストして作業を行うためのオプションを提供するだけです。

単一行と複数行の提案を混在させる必要はありません。両方をサポートできるという点で、欠点は非常に似ているが構文が異なる2つの方法があることです。

私は単一行のものを削除したいと思います。 エイリアンコードアイランドは目立つはずです。さもないと、何が起こっているのか誰も理解できません。

@ yecril71pl私は主に、発見の観点から、マークダウンを頻繁に書くためかもしれません。 また、多くのサンプルスクリプトは、各単一行が独立したプロセスである状態が保持されることを期待しているため、単一行ではなく複数行である可能性があります。

チームディスカッションやJeffreyとの話し合いでは、PowerShellスクリプト内で他の言語を実行したい人に反対するべきではありません。

絶対に100%ですが、それは言語に直接組み込む必要があるという意味ではありません。

@ yecril71plが指摘したように、私たちは他の言語を直接サポートしていませんが、そのコードを解釈して実行するために別のプロセスに依存しています。 ここでのシナリオは、ユーザーがpythonまたはbashスクリプトのブロックを見て、PowerShellスクリプト内でそのまま使用したいというものです。

それはすでにヒア文字列で行うことができますよね? これが既存の方法に比べてどのような利点を提供するかについて少し詳しく説明していただけますか?

また、なぜpythonとbashで停止するのですか? なぜC#、CIL、C ++ではないのですか?

人々がこれをすることを要求するものは何もありません。 必要に応じて、他のスクリプトをPowerShellに移植することもできます。 これは、ユーザーがPowerShellにカットアンドペーストして作業を行うためのオプションを提供するだけです。

私はそれを使わざるを得ないと思うので、私はこれに反対していません。 言語の観点から維持するのが難しく、編集者にとって悪夢であり、最終的にはいくつかの言語を知らない限り読めないスクリプトを奨励するので、私はそれが好きではありません。


実際、これはこのスレッドの元のトピックとはかなり異なる概念であり、はるかに広い意味を持っています。 新しい問題を作成することをお勧めします。

それはすでにヒア文字列で行うことができますよね? これが既存の方法に比べてどのような利点を提供するかについて少し詳しく説明していただけますか?

ユニバーサルコードエディタはそれらを検出して適切に装飾することができますが、エディタは内部に何があるのか​​わからないため、 @'で行うことは何もありません。

また、なぜpythonとbashで停止するのですか? なぜC#、CIL、C ++ではないのですか?

彼らはスクリプト言語ではないので?

ユニバーサルコードエディタはそれらを検出して適切に装飾することができますが、エディタは内部に何があるのか​​わからないため、 @'で行うことは何もありません。

編集者は、 bash -c @'にコードフェンスと同じくらい簡単にbashが含まれていることを知ることができます。 また、難しい部分は、コードのセクションがどの言語であるかを決定することではなく、言語サーバーと構文ハイライターをジャグリングすることです。 多大な時間と労力を費やさずに機能する唯一の方法は、本質的にここの文字列のようにレンダリングすることです。

彼らはスクリプト言語ではないので?

C#とC ++には、どちらもスクリプト指向のサブセットがあります。 そうしなかったとしても、「スクリプト言語」は主観的なものであり、実際の定義はありません。 含めると見なされるものと考慮されないものの明確な境界としては役立ちません。

C#とC ++には、どちらもスクリプト指向のサブセットがあります。 そうしなかったとしても、「スクリプト言語」は主観的なものであり、実際の定義はありません。

言語は、通常interpet options… script arguments…を呼び出す場合の(スタンドアロンの)スクリプト言語であり、その呼び出しは、一時的なものとインタプリタ専用のものを除いて、意図したもの以外は何も残しません。 また、通常、実行するにはインタプリタのコピーが必要であることも意味します。 この方法では実行できない埋め込みスクリプト言語があります。

@SeeminglyScience

それはすでにヒア文字列で行うことができますよね? これが既存の方法に比べてどのような利点を提供するかについて少し詳しく説明していただけますか?

今日、人々はヒア文字列を使用できます。または、正しく取得する方法を理解できれば、ネイティブコマンドに渡されたすべての引数をエスケープできます。 ここでの目的は、カットアンドペースト(Stackoverflow)シナリオの新規ユーザーが簡単にできるようにすることです。

また、なぜpythonとbashで停止するのですか? なぜC#、CIL、C ++ではないのですか?

ここでサポートされているシナリオは、ネイティブコマンドに渡されるテキストのブロックです。 その呼び出し規約をサポートしている場合は、どの言語もサポートできます。 一時ソースファイルを作成してコンパイルするという提案はありません。

私はそれを使わざるを得ないと思うので、私はこれに反対していません。 言語の観点から維持するのが難しく、編集者にとって悪夢であり、最終的にはいくつかの言語を知らない限り読めないスクリプトを奨励するので、私はそれが好きではありません。

混合言語の構文の色付けが行われることは期待できません。 別の言語のネストされたスクリプトは、単調になります。

実際、これはこのスレッドの元のトピックとはかなり異なる概念であり、はるかに広い意味を持っています。 新しい問題を作成することをお勧めします。

提案された実装は元の問題とは異なりますが、問題は同じであり、カットアンドペーストと「正常に機能する」シナリオです。

今日、人々はヒア文字列を使用できます。または、正しく取得する方法を理解できれば、ネイティブコマンドに渡されたすべての引数をエスケープできます。 ここでの目的は、カットアンドペースト(Stackoverflow)シナリオの新規ユーザーが簡単にできるようにすることです。

そうですが、実際にはどのように簡単ですか? 私はそれが主観的であると思いますが、これらは私にはそれほど変わらないようです:

~~~ powershell
$ a = `` `bash
見つける。 -iname * $ pdf -print0 | xargs -0 ls -ltr

~~~

vs

```powershell
$a = bash -c @'
   find . -iname *$pdf -print0 | xargs -0 ls -ltr
'@

後者が何が起こるかについてかなり明確であることを除いて、それらはほとんど同じように見えます。

ここでサポートされているシナリオは、ネイティブコマンドに渡されるテキストのブロックです。 その呼び出し規約をサポートしている場合は、どの言語もサポートできます。 一時ソースファイルを作成してコンパイルするという提案はありません。

さて、C#は一時的なソースファイルを必要としません。 たぶんCILでもないでしょう(C ++についてはわかりません)。 いずれにせよ、実行可能ファイル(bash / python / cmdなど)を呼び出すための厳密な構文糖衣構文であるコードフェンスは私を混乱させます。 コードフェンスは、言語サポートimoを意味し

混合言語の構文の色付けが行われることは期待できません。 別の言語のネストされたスクリプトは、単調になります。

それでも、tmLanguageベースのパーサーにとっては悪夢です。 彼らはatmを期待する構文をほとんど処理できません。 それ以上に、もしそうなら、なぜそれがここの文字列と違うのかわかりません。

提案された実装は元の問題とは異なりますが、問題は同じであり、カットアンドペーストと「正常に機能する」シナリオです。

公平ですが、以前に提案されたソリューションについて議論するために、すでに145のコメントがあります。 特に、このスレッドはすでに結論に達しているため、新しい専用スレッドへの関与が増える可能性があります。

さて、C#は一時的なソースファイルを必要としません。 たぶんCILでもないでしょう(C ++についてはわかりません)。 いずれにせよ、実行可能ファイル(bash / python / cmdなど)を呼び出すための厳密な構文糖衣構文であるコードフェンスは私を混乱させます。 コードフェンスは、言語サポートimoを意味します。

これに関する@SeeminglyScienceのコメントをエコーし​​たいだけです。 ライブラリMicrosoft.CodeAnalysis.CSharp.Scriptingを使用したコンパイルを伴わずに、 C#スクリプトます。 これが、dotnet-interactiveがC#Jupyterカーネルで使用するものです。 したがって、ユーザーがそのような構文でC#スクリプトまたはF#スクリプトのサポートを要求することは不合理ではないかもしれません。

PowerShellのコードフェンシング構文は、ネイティブコマンドを呼び出すためのものであると言えます。これにより、理論的には次のことが可能になります。

    ```c:\mypath\MyArbitraryExe
        args to my arbitrary executable
    ```

しかし、それは、 @ SeeminglyScienceが呼びかけたように、言語サポートを意味する

これは理論的にこれを可能にします

引数ではなくスクリプトを内部に配置すると、スクリプトは入力ストリームと同等になります。 また、これがSOサポートを提供することを意図している場合は、フルパスを許可しないでください。

引数ではなくスクリプトを内部に配置すると、スクリプトは入力ストリームと同等になります

スクリプトはbash / cmd / pythonの引数です。

また、これがSOサポートを提供することを意図している場合は、フルパスを許可しないでください。

次に、この例に切り替えます。

〜powershell$ a = ipconfig /all

または、最初に任意のexeファイルをパスに追加します。

引数ではなくスクリプトを内部に配置すると、スクリプトは入力ストリームと同等になります

スクリプトはbash / cmd / pythonの引数です。

それらのいずれも、位置引数としてスクリプトを渡すことを許可していません。 CMDはバッチファイルさえ許可しません。

また、これがSOサポートを提供することを意図している場合は、フルパスを許可しないでください。

次に、この例に切り替えます。

$ a = `` `ipconfig
/すべて

それはうまくいきません。

このマークダウンのアイデアが機能するためには、非常に恣意的に非常に多くの特別なケースを作成しているようです。

また、これがMarkdownでもサポートされている主な理由は、構文の強調表示のためです。 このようなものを言語に追加すると、それは常に要求になります。

これは効果的な解決策ではありません。

これについて@jpsnoverシジルとしてシェバン#!を提案しました

私の2セントを追加するだけで、解決策が発表された後にこの議論を再開するのは間違いだと思います。 個人的には、shebangとmarkdownの両方の構文が嫌いです(そして両方とも大きな変更です)。

誰かが明らかにもっと良いものを思いついた場合、私は議論を再開してもかまいません。 機能が出荷された後よりも、それを行う方が確かに良いです。 #!やマークダウンアプローチが、ネイティブexeに「PowerShellで混ぜ物をしていない」コマンドライン文字列を提供するためのより良い解決策だとは思いません。 慣れるために試してみる必要があるかもしれませんが、最初の反応は...ええと、ええと。

_私たち(およびPowerShell)がネイティブ実行可能ファイルを実行していることがわかっている場合、なぜ「ネイティブオペレーターを呼び出す」必要があるのですか?_

PowerShellが入力文字列を解析してCommandAstを取得すると、PowerShellはコマンドの検出を行います。
コマンドがネイティブコマンドの場合、PowerShellはastをNativeCommandProcessorに変換します。
Astエクステント(つまり入力文字列)を再解析するケースに新しい(実験的なNativeCommandProcessor)を実装して、ネイティブの実行可能ファイルの名前/パスと残りの文字列を1つまたは複数のOSルールの引数として取得できます。

ユーザーがシェルからコピー&ペーストしたい場合は、「cmd」と入力する必要があります"または" bash"-編集しなくても機能します。
ユーザーがネイティブコマンドラインをコピーして貼り付けたい場合g++ timer.cpp @conanbuildinfo.args -o timer --std=c++11ように機能します。

ユーザーがシェルからコピー&ペーストしたい場合

そのためにGet-/Set-Clipboardがあります。

Astエクステント(つまり入力文字列)を再解析して、ネイティブの実行可能ファイルの名前/パスと残りの文字列を1つまたは複数のOSルールの引数として取得する場合。

ここでの私の考えは、これを行うことはあなたのどちらかであるということです:

  • コマンドASTを非効率的に解析し、後でエクステントを文字列として再解析して、元のASTを破棄するか、または
  • ASTを取得し、それを文字列に再変換しようとします(現在のNativeCommandProcessorの方法)が、そうすると物事が失われます

したがって、代わりに、最初から文字列を保持する必要があります。 さて、間違いなくPowerShellにはすでに3種類の文字列トークンがあると思いますが、この議論の主な要求は、物事を逃れたくないようです。 すべての文字列はターミネータをエスケープできる必要がありますが、そこで説明されている解決策は、ターミネータとして改行を使用し、改行をエスケープできないようです(常にセミコロンがあります)。

私は改行のみのターミネーターに完全に夢中になっているわけではありませんが、何も逃げたくないという唯一の解決策のようです。 基本的に、これにより、今日の行コメントと同様に「ネイティブ呼び出し演算子」がトークン化されます。演算子から行の終わりまでは、「ネイティブシェル」に渡される文字列です。

そう:

--% ps -o pid,args -C bash | awk '/running_script/ { print $1 }'

次のようにトークン化します:

--% ps -o pid,args -C bash | awk '/running_script/ { print $1 }'
|-||-----------------------------------------------------------|
 |                                  \
Native call operator        Invocation to be passed to native shell

(文字列は--%直後から始まるため、 --%直後のスペースもネイティブシェルに送信することに注意してください)

次に、このトークンは次のような非常に単純なASTでラップされます。

// We need to carefully work out what AST this inherits from
// This syntax has almost no interoperability with PowerShell by design,
// so can't implement fields like redirections or backgrounding faithfully.
// But in order to participate in pipelines and similar, would need to extend a more concrete class
public class NativeCallInvocationAst : StatementAst
{
    public string NativeInvocation { get; }
}

次に、これがコンパイルされてパイプに送信された後、これは新しいネイティブコマンドプロセッサを使用して、文字列を引数としてネイティブシェルに直接送信します。

それはすべて実装可能に思えますが、私の頭の中のいくつかの質問は次のとおりです。

  • ネイティブシェルは構成可能ですか? そうでない場合、どのようにそれを正当化するのですか? もしそうなら、それは構文の一部として明示的(構文を複雑にする)にするべきですか、それとも設定変数として実装するべきですか(発見と管理を難しくします)?
  • そのような実装は発見可能であり、人々を混乱させないでしょうか? ユーザーは、PowerShellがここで行っていることがどれほど少ないか、または|& 、さらには文字列を使用したときに何が起こっているかを理解できますか?
  • ここでは、1行の逐語的な文字列によっていくつのシナリオが処理されますか? 多くの人が複数行の呼び出しを望んでいることを確認するためだけに、これを実装しますか? これらの制約を追加するのに十分な大きさで、一重引用符をエスケープするようなことを避ける必要がありますか?
  • これは、まったく新しい言語構文の非常に特殊なシナリオのようです。 新しい逐語的な文字列構文を作成している場合、なぜそれをネイティブ呼び出しの概念に直接結合するのですか? 新しい呼び出しメカニズムを作成している場合、なぜそれを他のシェルの概念に直接結合するのですか? 優れた構文と優れた言語構造は、構文的にも機能的にも構成され、言語自体に過度に組み込まないようにします(代わりに、ユーザーがプログラムとしてアセンブルするための要素のプラットフォームを提供します)—提案されたネイティブ呼び出し構文は基準を満たしていますか新しい基本構文をプログラムに構成するには? この問題を簡単な方法で解決するが、他の問題を解決するために構成できるようにビルディングブロックを切り離しておくことができる、より良い代替アプローチはありますか?
  • 他のシェルまたは他の言語がこれを実装しますか、それともすでに持っていますか? 構文レベルで、または他のレベルで? もしそうなら、どのように?

ここでの私の考えは、これを行うことはあなたのどちらかだということです

@rjmholt CommandAstには、入力文字列を持つExtentプロパティがあります。 再解析は、Windowsでは最初のスペースで分割するか、Unixではスペースで分割するのと同じくらい簡単です。 ですから、弦の中で何も失わず、良いパフォーマンスが得られると思います。

ただし、これは実装されますが、テストするための一連のユースケースが必要だと思います。 以下を「提案」させてください。

  • ユースケース1:引用/エスケープルールについて知らなくても、単一のexeリテラル(補間なし)呼び出しを機能させたいg++ timer.cpp @conanbuildinfo.args -o timer --std=c++11 。 これに対する現在の回避策は、引用するものを理解することです。例: g++ timer.cpp '@conanbuildinfo.args' -o timer --std=c++11より複雑な例には、複数行にまたがるコマンドラインが含まれる場合があります。
tar -cvpzf /share/Recovery/Snapshots/$(hostname)_$(date +%Y%m%d).tar.gz \
    --exclude=/proc \
    --exclude=/lost+found 

現在の回避策(バッククォートを\交換)例:

tar -cvpzf /share/Recovery/Snapshots/$(hostname)_$(date +%Y%m%d).tar.gz `
    --exclude=/proc `
    --exclude=/lost+found
  • ユースケース1a:PS補間を使用した単一のexe呼び出しを機能させたい例: g++ $CppFile @conanbuildinfo.args -o timer --std=c++11 。 これに対する現在の回避策は、何を引用するか(シングルまたはダブル)、何をエスケープするかを理解することです。例: g++ $CppFile '@conanbuildinfo.args' -o timer --std=c++11より複雑な例には、複数行にまたがるコマンドラインが含まれる場合があります。
tar -cvpzf "/share/Recovery/Snapshots/${ComputerName}_`$(date +%Y%m%d).tar.gz" \
    --exclude=/proc \
    --exclude=/lost+found 

現在の回避策、最初の引数を二重引用符で囲み、バッククォートを\に交換し、 `$(date + ...)の先頭で$をエスケープします。

  • ユースケース2:別のシェルでリテラルパイプラインコマンドを実行したい例: ps -o pid,args -C bash | awk '/running_script/ { print $1 }'およびwsl ls $foo && echo $PWD 。 _これが前のユースケースとは別のユースケースである必要があるかどうかはわかりません。_現在の回避策は、bashコマンドを引用することです(例: bash -c 'ps -o pid,args -C bash | awk ''/-bash/ { print $1 }''' 。 このユースケースには、複数行の文字列も含まれる場合があります。例:
ps -o pid,args -C bash | \
awk '/running_script/ { print $1 }'
  • ユースケース2a:PS補間を使用

  • ユースケース3:作業を継続するには、 npm run $scriptNameが必要です

interpolating文字列、つまりg++ $CppFile @conanbuildinfo.args -o timer --std=c++11ユースケースがあるべきかどうかという疑問がありますか、それとも単にそれをパントして、現在のエスケープルールがこれをカバーしていると言うのでしょうか?

これらは適切な(またはすべての)ユースケースではない可能性がありますが、ユースケースを文書化し、この機能について説明するときにそれらを参照できると便利だと思います。そうしないと、機能が実際にどのように対処するか(またはそうでないか)に迷いやすくなります。 )顧客のユースケース。

また、2番目のユースケースでは、「シェル呼び出し」が必要なようです。 しかし、最初のものがそうするかどうかはわかりません。 exeを直接呼び出すことができるようです。

@rkeithhill以前の投稿で完全を

@oising 、私もあなたの思慮深い応答に感謝します。

ins ...は、 & cmd --% ...ができないことを何に与えますか?

現在の_parameter_(シンボル)形式の--% (その動作は保持したいと思います)は、_multi-command_ cmdサポートしていないため、 cmd /c --%は使用できません。最初の引用符で囲まれていない|が_PowerShellの_パイプ演算子として解釈され、 &が逐語的に渡される場合、 cmdコマンドライン(またはエスケープ文字として^ )。
同じは、Unix上で適用されます--% 、一般的にほぼ無用である、としてsh -cあるため、完全に失敗したsh _single_引数(例えば、のようにコマンドラインを期待しますsh -c --% echo hi echoだけがコマンドとして実行されるため、 sh -c --% echo hiは空の行を生成します。

insは、パススルーコマンドラインを_単一の文字列として_渡すことで区切る必要があるため、これらの問題を解決し、前述のように、文字列補間を使用して_PowerShell_変数と式の値を組み込むこともできます。

そして後者は、提案された--% _ statement_が_行き止まりの通り_である理由を私たちにもたらします:

  • 既存のコマンドラインをそのまま実行することから、PowerShell変数と式の値を組み込むことへの移行パスはありません。

    • これを実現する唯一の(あいまいで面倒な)方法は、対象のPowerShell値を格納し、参照できる_補助環境変数_を定義することです(シェル-適切に%...%または$... )ネイティブコマンドライン。
  • --%ステートメントをより大きなPowerShellパイプラインに組み込むことができないという厄介な問題があります。

    • ネイティブシェルを呼び出す正当な_non_-cut-and-pasteの理由があることに注意してください。この統合が期待される場合、 具体的には、_rawバイトデータ_を(中間)パイプラインに渡し、末尾の改行なしで_strings_を送信するには、ネイティブパイプを使用する必要があります。実際の例については、このSOの回答を参照してください。
  • --% _parameter_がUnixで事実上役に立たないという厄介さもあり、奇妙な非対称性が生じます。 --% _statement_がUnixでも機能する場合は、 --% _parameter_ ? (例えば、
    /bin/echo --% 'hi "noon"'は、 echo _two_引数を受け取り、逐語的に'hinoon'受け取るため、(予想されるhi "noon"ではなく)逐語的に'hi noon' echoを生成します。 noon' 、一重引用符はデータとして保持され、二重引用符は削除されます)。


insは、 --%ステートメントの代替案として、理想的にはcmd /csh -c周りの_便利なラッパー_ですが、実際には_必須_です。

  • sh -c '...'直接呼び出すと、現在、 "が埋め込まれた引数が適切に渡されないため、#1995が修正されていない限り、Unixでは少なくとも_一時的に_。

  • Windows上で_Invariably_、あなたがコマンドライン_As-is_に合格する必要があるため、 cmd経由でlpCommandLineのパラメータCreateProcessこれは( --%行うことができないパラメータ_one_コマンドに制限されているため); あるいは、コマンドラインを"..."囲まれた_単一の文字列_として再度渡そうとすると、#1995が原因で堅牢に機能しません。


_argument_の受け渡しの問題は、_via stdin _( insもサポートでき、サポートする必要があります)を実行するコマンドラインを提供することで回避できます。つまり、コマンドライン/スクリプトテキストをシェル実行可能ファイルに_パイプ_します。

  • Unixでは、これは問題なく機能します。これは、_stdin_を介してコードをsh渡すことは、実行のために_script file_を渡すことと本質的に同じであるためです( sh -c '<code>' is同様)。
PSonUnix> @'
echo '{ "foo": "bar" }' | cat -n
'@ | sh

     1  { "foo": "bar" }
  • 残念ながら、Windowsではcmdはそのような入力をうまく処理しません。ロゴを出力し、実行前に各コマンドをプロンプト文字列とともにエコーします。
PSonWin> 'date /t & ver' | cmd

Microsoft Windows [Version 10.0.18363.836]
(c) 2019 Microsoft Corporation. All rights reserved.

C:\Users\jdoe>date /t & ver
Sun 07/26/2020

Microsoft Windows [Version 10.0.18363.836]

C:\Users\jdoe>

悲しいことに、PowerShell自体も同様に役に立たない動作を示します。#3223を参照してください。


shおよびすべての主要なPOSIXのようなシェル( dashbashkshzsh )と同様に、ほとんどのスクリプト言語は適切に_do_します。 pythonnoderubyperlなどのstdin-as-script入力をサポートします。

PS> 'print("hi")' | python

hi

_PowerShell_変数と式の値を組み込むために、文字列補間/連結を使用するオプションがあります。

PS> $foo = 'bar'; "print(`"$foo`")" | python

bar

または、インタプリタの引数受け渡し機能を使用します。

PS> @'
import sys
print(sys.argv[1])
'@ | python - bar

bar

上記で、特別な構文( --%ステートメント、 #!ステートメント、Markdownコードブロックのいずれも)がまったく必要ないことます。呼び出し元のPowerShellスクリプトから値を組み込む機能。

使用するネイティブシェルの構成可能性について:予測可能性のために、提供するべきではないと思います。 別のシェルをターゲットにしたいユーザーは、コマンドラインをそのシェルの特定の実行可能ファイルにパイプするか、#1995が修正されたら、引数として渡すことができます。

  • 議論の余地のあるバリエーションは、 /bin/bashをターゲットにすることです( /bin/shへの(ありそうもない)フォールバックを伴う)-公開されたコマンドラインがPOSIXで義務付けられた機能のみに依存することを望む一方で、Bash-ismsを備えたコマンドライン(すべての/bin/sh実装がサポートすることを期待できるわけではない非POSIX機能)は、 bash普及を考えると、おそらくそこにあります。

@joeyaiello

この特定の機能の利点は、#1995の影響よりもはるかに重要であると私は考えています。

このカットアンドペースト機能を(主に_インタラクティブな_利便性のために)(厄介で機能が制限された)一級市民にするために私たちが費やすのと同じくらいの努力を費やしているのに対し、PowerShellは基本的に空を渡すことができないのは気が遠くなるようなことです。引数と"文字が埋め込まれた引数。

しかし、私は人々が野生の集団で#1995を打つのを見ていません

私はそうします、そして私が以前に議論した

繰り返しになりますが、PowerShellが現在行っているように、次のことを行うシェルには深刻な問題があると主張

# On Unix
PS> /bin/echo '{ "foo": "bar" }'

{ foo: bar }

@rjmholt CommandAstには、入力文字列を持つExtentプロパティがあります。 再解析は、Windowsでは最初のスペースで分割するか、Unixではスペースで分割するのと同じくらい簡単です。 ですから、弦の中で何も失わず、良いパフォーマンスが得られると思います。

ええ、私はそこの引き分けを理解しています、そしておそらくそのシナリオでのASTの割り当てはひどいものではありません(言語は単純な構文のために不必要な割り当てを生成するべきではないと私は主張しますが)。 しかし、あなたがしなければならないのは、bash / cmdが文字列として認識し、PowerShellが問題を引き起こし始めない入力を想像することだけです。

現在のPowerShellでは解析しません:

--% my_command "\" "

解析しますが、スペースで分割すると間違った結果になります。

--% my_command "\"    "\"

(文字列に4つのスペースを送信する必要がありますが、PowerShellは2つの文字列が配列で区切られていることを確認します)

@rjmholt上記のコメントの下部にあるすべてのすばらしい質問。これもまた、正しい答えは次の

以前のコメントで使用するネイティブシェル実行可能ファイルについての質問に対処しましたが、次の点についてです。

他のシェルまたは他の言語がこれを実装しますか、それともすでに持っていますか? 構文レベルで、または他のレベルで? もしそうなら、どのように?

_explicit delimiters_を使用せず、_interpolation_を許可せずに、構文レベルでこれを行った他の言語を私は知りません。
たとえば、 perlはシェルコマンドを実行するための`...`ため、Unixのスクリプトから次のコマンドを実行できます。
my $foo='/'; print `ls $foo | cat -n`

重要な側面は、明示的な区切り文字の使用と、呼び出し元からの値を組み込む機能です。どちらも、 --%ステートメントの現在の提案にはありません。

前に述べたように、このアプローチを新しい_operator_(またはある種の区切り文字ベースのオプションで補間する構文)に使用することはできますが、それだけの価値はないと思います。
ins "ls $foo | cat -n" (またはhere-stringバリアントを使用)は、言語に複雑さを追加することなく実行できます。

perlは、(適切な)構文レベルのソリューションを提供します。これは、それ自体がシェルではないためですが、シェル呼び出しを可能な限り便利にしたいためです。

対照的に、私たちは(あまりにも)シェルであり、追加の構文なしでシェルスタイルの呼び出しを直接提供します(現在欠陥がありますが、#1995を参照してください)。
_異なるシェルの_呼び出しをできるだけ簡単にするための特別な構文を提供することは不要のようです。

@iSazonov

_私たち(およびPowerShell)がネイティブ実行可能ファイルを実行していることがわかっている場合、なぜ「ネイティブオペレーターを呼び出す」必要があるのですか?_

PowerShellが入力文字列を解析してCommandAstを取得すると、PowerShellはコマンドの検出を行います。
コマンドがネイティブコマンドの場合、PowerShellはastをNativeCommandProcessorに変換します。
Astエクステント(つまり入力文字列)を再解析するケースに新しい(実験的なNativeCommandProcessor)を実装して、ネイティブの実行可能ファイルの名前/パスと残りの文字列を1つまたは複数のOSルールの引数として取得できます。

ユーザーがシェルからコピー&ペーストしたい場合は、「cmd」または「bash」と入力する必要があります。これは編集しなくても機能します。
ユーザーがコピーアンドペーストを希望する場合、ネイティブコマンドラインはg++ timer.cpp @conanbuildinfo.args -o timer --std=c++11ます。

しかし、それをすべて実行した場合、ネイティブコマンドでPowerShell構文を使用できなくなるのではないでしょうか。 それで、 sc.exe query $serviceName$serviceNameをリテラル文字列として渡すように?

しかし、それをすべて実行した場合、ネイティブコマンドでPowerShell構文を使用できなくなるのではないでしょうか。 したがって、 sc.exe query $serviceName$serviceNameをリテラル文字列として渡すように?

--%オプションは、そのニーズに対応することを目的としたものではありません。

sc.exe query $serviceName&"<cmd>"によって処理されます

--%オプションは、そのニーズに対応することを目的としたものではありません。

sc.exe query $serviceName&"<cmd>"によって処理されます

確かに、それは@iSazonovが言及していることではないと思います。 ネイティブコマンドのパラメーターバインディングの動作方法の一般的な変更を提案しているように読んでいます。

確かに、それは@iSazonovが言及していることではないと思います。 ネイティブコマンドのパラメーターバインディングの動作方法の一般的な変更を提案しているように読んでいます。

主よ、私はそうしないことを望みます。

主よ、私はそうしないことを望みます。

アブストラクトをブレインストーミングしていると、明白なことを忘れがちです。 公平を期すために、私たちは皆それを読み、それがどれほど壊れるかに気付かずにすぐに実装を考え始めました。

または、明らかな何かが欠けていて、それは提案されているものではありません😁

@essentialexch 、明確にするために、re:

sc.exe query $serviceName&"<cmd>"によって処理されます

& "<cmd>"は、 <cmd>が単なるコマンド_nameまたはpath _、_引数を含まない_に評価される場合にのみ機能します-引数は個別に個別に渡す必要があります-それ自体は"...."必要としません展開される変数参照の引用(例:
$exe = 'findstr'; & "where.exe $exe"は設計上失敗します。 & "where.exe" $exe必要があります(ここでは二重引用符はオプションです。省略した場合、 &もオプションです))

確かに、それは@iSazonovが言及していることではないと思います。 ネイティブコマンドのパラメーターバインディングの動作方法の一般的な変更を提案しているように読んでいます。

私の提案は、#1995を(重大な変更を加えて)できるだけ簡単に修正することです。 原因の補間は機能しません。 当然のことながら、これは最終的な提案ではありません。修正を数分で実装する方法をデモします。 また、 @ mklement0も指摘しているように、ネイティブ演算子の呼び出しはまったく必要ないことを主にデモします。

解析しますが、スペースで分割すると間違った結果になります。

@rjmholtはい、でもあなたはその考えを理解していると思います。
CommandAstの最初の子はStringConstantExpressionAstで、ネイティブコマンドはBareWordです。 CommandAst Extentからベアワードを切り取り、ast-sを変更せずにパラメーターリストを取得できます。 ただし、パラメータリストを保持するために新しいastを追加することもできます。
以下で説明を要約したいので、説明に時間を費やします。複雑に見える拡張機能を実装する必要があると思いますが、単純で__下位互換性を簡単にオプトアウトして__実装できると思います。


@ SteveL-MSFTの最初の提案の意図は、重大な変更を回避することだったと思います。
@ TSlivede@ mklement0に同意します。この議論では、#1995や#12975のようなすべての_基本的な_問題を解決できるわけではないため、新しい構文は必要ないことが示されました。 一方で、それは言語に複雑さを追加しますが、逆に、ネイティブアプリケーションでの作業を_単純化_したいのです。

__前進する唯一の方法は、重大な変更以上を行うことです。__(その後、新しい演算子またはコマンドレットが一部のシナリオでも役立つ場合があります。)


ユースケースとユーザーの期待の要約から始める必要があります。
上記@rkeithhillすばらしい投稿をご覧ください

  1. ユーザーは補間を有効/無効にしたい。
    PowerShellには、一重引用符と二重引用符が付いた文字列/ヒア文字列が既にあります。
    私たちの目標は、その適用/改良/強化の方法を理解することです。
  2. ユーザーは実行可能ファイルまたはシェルを実行したい

    • 任意の実行可能ファイル-コマンドはアプリ名で始まり、引数に従います

      • 補間あり/なし

      • シングルライン/マルチライン

    • 引数は_script_であるため、シェルはおそらく特殊なケースです。

      • コピーアンドペーストのシナリオでは、ユーザーは補間を必要とせず、単一行と複数行を必要とします

      • スクリプトシナリオでは、ユーザーは補間を有効/無効にし、単一行と複数行を必要とします

    考え:
    これにより、コピーアンドペーストシナリオの動作をデフォルトにする必要があると考えられます。
    行末記号は実行可能ファイルに依存します(bashでは `、PowerShellでは`)。 これにより、次のように考えられます。
    (1)シェルは、実行可能ファイルとして明示的に指定する必要があります。
    (2)おそらく、複数行の実行可能ファイルはシェルを使用して呼び出すか、特別な解析を行う必要があります(ターミネーターを削除し、エスケープの問題にフォールバックする引数リストを作成するため)
    (3)PSReadlineでコピーと貼り付けのシナリオに対処できます。 バッファを正しいPowerShellコマンドに変換できます。

  3. ユーザーは単一行と複数行を望んでいます。

    • おそらく、前述のようにいくつかのシナリオに対処するために、ヒア文字列を1行に拡張する必要があります。
    • 2-(2)を参照してください-常に複数行にシェルを使用するか、特別な解析を実装してください

@TSlivede@ mklement0は以前の考えと結論を更新する可能性があるため、これ以上書きたくありませんが、これは現在、重大な変更の受け入れに基づいている可能性があります。 新しい問題を開き(そしてすべての古い問題を閉じて)、すべてのユースケースを列挙し(@ @ Pesterテストを作成するように依頼します-問題を修正するための素晴らしいステップです。

Invoke-Shell(Invoke-NativeShell)、Test-Arguments(ネイティブアプリがユーザーのヘルプを取得して表示することを示すechoargs.exeなど)、Convert-Arguments(Convert-Arguments(ユーザー入力を右エスケープ引数に変換します)。

PS:上で示したように、単一行の動作は、実行時に下位互換性のために簡単にオプトアウトできます。

行末記号は実行可能ファイルに依存します(bashでは `、PowerShellでは`)。

\は、 bash行末記号ではありません。

原因の補間は機能しません。 当然のことながら、これは最終的な提案ではありません。修正を数分で実装する方法をデモします。 また、 @ mklement0も指摘しているように、ネイティブ演算子の呼び出しはまったく必要ないことを主にデモします。

リポジトリを削除しただけで、数分ですべてのバグを修正できるのと同じ方法です。 それはあなたが提案しているかなり大きな休憩です。 たとえ架空のものであっても、それがどのように役立つかはわかりません。

たとえ架空のものであっても、それがどのように役立つかはわかりません。

@SeeminglyScience私たちはさまざまな状況にあるようです。 パーサーを壊すことなく、壊れた変更として単一行のネイティブ呼び出しの修正を実装できると言います。 つまり、実装する新しい動作に関係なく、その場で動作を切り替えることもできます。

つまり、実装する新しい動作に関係なく、その場で動作を切り替えることもできます。

私が見逃しているのは、(ネイティブオペレーターの呼び出しのように)明示的に要求せずに、その動作をその場でどのように切り替えるかということだと思います。

@iSazonov

_私たち(およびPowerShell)がネイティブ実行可能ファイルを実行していることがわかっている場合、なぜ「ネイティブオペレーターを呼び出す」必要があるのですか?_

PowerShellが入力文字列を解析してCommandAstを取得すると、PowerShellはコマンドの検出を行います。
コマンドがネイティブコマンドの場合、PowerShellはastをNativeCommandProcessorに変換します。
Astエクステント(つまり入力文字列)を再解析するケースに新しい(実験的なNativeCommandProcessor)を実装して、ネイティブの実行可能ファイルの名前/パスと残りの文字列を1つまたは複数のOSルールの引数として取得できます。

ユーザーがシェルからコピー&ペーストしたい場合は、「cmd」または「bash」と入力する必要があります。これは編集しなくても機能します。
ユーザーがコピーアンドペーストを希望する場合、ネイティブコマンドラインはg++ timer.cpp @conanbuildinfo.args -o timer --std=c++11ます。

それが何を意味するのかを確認したいと思います。外部の実行可能ファイルを呼び出すときに、すべてのPowerShell構文を本質的に無視することを提案していますか?

具体的には:たとえば、実行していることを示唆していますか

/bin/echo (1..5)

PowerShellでは1 2 3 4 5を出力しなくなりますが、代わりにリテラル(1..5)出力する必要がありますか?

それが実際にあなたが提案していることであるならば、私が言わなければならないよりも:それはひどい考えだと思います。

これは物事を単純化するものではなく(外部実行可能ファイルは内部コマンドレットと構文的に異なる動作をするようになりました)、#1995IMHOでは何もする必要もありません...

@rjmholt
上記

  • 他のシェルまたは他の言語がこれを実装しますか、それともすでに持っていますか? 構文レベルで、または他のレベルで? もしそうなら、どのように?

私の頭に浮かぶ唯一のことは、ipythons !演算子です:

ipython出力で!ps -'fax' || trueを実行する:

  261 pts/0    Sl     0:00          \_ /usr/bin/python /usr/bin/ipython
  311 pts/0    S      0:00              \_ /bin/bash -c ps -'fax' || true
  312 pts/0    R      0:00                  \_ ps -fax

psは引数の前後に引用符を表示しませんが、 ps -'fax' || trueは実際にはbashへの単一の引数として指定されます。)

ただし、この機能では、Python変数をそのコマンド( {pyvar} )に補間することができます。

@ mklement0と同様に、ipythonはこれのみを実装します

それ自体がシェルではないので

ipythonがpython構文のみを許可する場合、シェルとしてはあまり有用ではないため、この構文がコマンドをbashに転送して、シェルとして使用できるようにします。 他のシェルを呼び出すための特別な構文を追加するのは非常に奇妙になるので、(#1995が解決するまで、私はそれがシェルであると言うことはありません)シェルすべき一方の主張にPowerShellの。

このようなものが何らかの理由で実際に実装された場合(うまくいけばそうではない)、「シェル演算子の呼び出し」として--%代わりに!を使用することをお勧めします。

!は、人々が推測するかもしれないものです(ipythonから(またはvimコマンドモードから、またはlessから、またはftp )その目的のために!を知っているため) )

--%は入力が難しく、推測される可能性は低く、最も重要なことです。現在の--%使用法は、「別のシェルにものを渡す」とほとんど共通点がないと思います。動作。 現在の--%は、cmd構文の1つの要素である変数置換をエミュレートします(完全ではありません)。 エスケープ文字^サポートしておらず、ファイルへのリダイレクトも許可していません。 現在の--%についていくらか役立つのは、逐語的なコンテンツをlpCommandLineに渡す機能だけですが、提案されている「シェル演算子の呼び出し」は得意ではありません。

提案された「シェル演算子の呼び出し」と現在の--%のもう1つの違い(すでに説明しました):一方はパイプで終わり、もう一方はそうではありません-新しいユーザーにとっては非常に混乱します。 !は、これまでにテストしたすべてのアプリケーション(ipython、vim、less、edなど)のシェルに|を転送します。

HELP about_Logical_Operators -S

ええ、 !自体は、言語の論理否定演算子であるため、問題があります。

ところで、代替案の1つは&! -一種の「ネイティブ/シェルの呼び出し」演算子です。

@TSlivedeが「何らかの理由でこのようなものが実際に実装された場合(うまくいけば)」と言ったときに、「うまくいけない」部分をもっと強調してます

  • $が_both_の変数sigilとして使用されている場合、_個々の引数を持つ_演算子/ステートメントはI-want-to-use-PowerShell-values-in-the-native-command-line問題をきれいに解決できません。 PowerShellおよびPOSIXのようなシェル。

  • _ネイティブコマンドライン全体の周りに明示的な区切り文字がない_演算子/ステートメントは、ネイティブコマンドラインの終わりの問題を解決できません(気にする場合と気にしない場合があります)。

@ PowerShell / powershell-委員会は本日これについて議論しました。 現時点では、最初の問題の説明や解決方法の設計について合意が得られていないようであるため、安定した設計でこれを7.1に組み込むことはできないと考えています。

@ PowerShell / powershell-委員会は本日これについて議論しました。 現時点では、最初の問題の説明や解決方法の設計について合意が得られていないようであるため、安定した設計でこれを7.1に組み込むことはできないと考えています。

182コメント!

これについていくつかの素晴らしい議論がありました! この問題に関する新しいコメントは引き続き監視します。 この問題とは関係なく、PSGalleryに公開されているInvoke-NativeCommandタイプのコマンドレットを実装することをコミュニティに推奨します。

https://github.com/PowerShell/PowerShell/issues/13068#issuecomment -662732627で妥協したが非常に便利な解決策があった場合、これを削除するのは残念だと思います。 コンセンサスが必要なことは承知していますが、妥協が最善の場合もあります。 いいえ、完璧ではありませんが、ワンライナーSOソリューションは非常に便利です。 少なくともこの一人の意見では。

@essentialexch明確にするために、PowerShellチーム内でのコンセンサスすらありません

これは延期されているので、ヘルパーの実装はどうですか

Invoke-Shell(Invoke-NativeShell)、Test-Arguments(ネイティブアプリがユーザーのヘルプを取得して表示することを示すechoargs.exeなど)、Convert-Arguments(ユーザー入力をに変換する)などのユーザー採用を簡素化する新しいコマンドレットを検討できます。右エスケープ引数)。

Test-Argumentsは非常に役立つと思います。

モジュールNativeInstall-Module Native -Scope CurrentUser )を公開しました。これ上記の@rkeithhillのコメントからのものです。

概念的な霧をクリアしたい場合は、ユースケースを別の方法で組み立てる必要があると思います。
_それらのどれも解析の変更を必要としません_。

ユースケース[ネイティブシェル呼び出し]:

プラットフォームネイティブシェル用に作成された_個別コマンド_(ユースケース1)または_マルチコマンドコマンドライン全体_(ユースケース2)を実行する必要があります_(この問題):

  • 別のシェルの構文を使用しているため、_it_が解析を実行するために、コマンド(行)を_単一の文字列として_ターゲットシェルに渡します。 PowerShellの文字列補間は、渡された文字列にPowerShell値を埋め込む機能を提供します(ユースケース2a)。
  • insInvoke-NativeShellは、これらのユースケースをカバーしています。
# Use case 1: Single executable call with line continuation, on Unix.
@'
tar -cvpzf /share/Recovery/Snapshots/$(hostname)_$(date +%Y%m%d).tar.gz \
    --exclude=/proc \
    --exclude=/lost+found 
'@ | ins

# Use case 2: Entire Bash command line (also with line continuation)
@'
ps -o pid,args | awk \
  '/pwsh/ { print $1 }'
'@ | ins

# Use case 2a: Entire Bash command line (also with line continuation) with string interpolation.
# Note the double-quoted here-string and the need to escape the $ that is for Bash as `$
$fields = 'pid,args'
@"
ps -o $fields | awk \
  '/pwsh/ { print `$1 }'
"@ | ins

# Alternative to use case 2a: pass the PowerShell value *as a pass-through argument*,
# which allows passing the script verbatim.
# Bash sees the pass-through arguments as $1, ... (note that the `awk` $1 is unrelated).
@'
ps -o $1 | awk \
  '/pwsh/ { print $1 }'
'@ | ins - 'pid,args'

here-string構文は最も便利ではありませんが(したがって、インラインバリアントを実装することをお勧めします-#13204を参照)、それを使用する必要はありません。 逐語的なコマンドの場合、 '...'使用できます。これには、_doubling_埋め込み'が存在する場合にのみ必要です。

また、これは「StackOverflow演算子」の合理的な代替手段です

次のPSReadLineキーハンドラーを$PROFILEファイルに配置すると、 Alt-vを使用して、逐語的なhere-stringを使用してinsへの呼び出しをクリップボードに入れることができます。現在のクリップボードのテキストが貼り付けられる場所。Enterは通話を送信します。

# Scaffolds an ins (Invoke-NativeShell) call with a verbatim here-string
# and pastes the text on the clipboard into the here-string.
Set-PSReadLineKeyHandler 'alt+v' -ScriptBlock {
  [Microsoft.PowerShell.PSConsoleReadLine]::Insert("@'`n`n'@ | ins ")
  foreach ($i in 1..10) { [Microsoft.PowerShell.PSConsoleReadLine]::BackwardChar() }
  # Comment the following statement out if you don't want to paste from the clipboard.
  [Microsoft.PowerShell.PSConsoleReadLine]::Insert((Get-Clipboard))
}

ユースケース[直接実行可能呼び出し]:

_PowerShell_の構文を使用し、_個別の引数_を使用して_単一の外部実行可能ファイル_を呼び出します(ユースケース1aおよび3)。

  • これはあらゆるシェルの中心的な使命であり、堅牢に機能することが非常に重要です。

    • PowerShellが、_its_を_as-is_で解析した結果の引数をターゲットの実行可能ファイルに渡すことができることに依存できる必要があります。 現在はそうではありません-#1995を参照してください
  • _PowerShellの_構文と_its_引数モードのメタ文字を理解する必要があります。

    • `がエスケープ文字として、および行の継続に使用されることに注意する必要があります。
    • PowerShellには、逐語的に使用するために引用符/エスケープを必要とする追加のメタ文字があることに注意する必要があります。 これらは( @は引数の最初の文字としてのみ問題があることに注意してください):

      • POSIXのようなシェル(Bashなど)の場合: @ { } ` (PowerShellによる事前の拡張を防ぎたい場合は$
      • cmd.exe( ) @ { } # `
      • 個別に` -そのような文字をエスケープします。 十分です(例: printf %s `@list.txt )。

#1995が修正されるのを待っている間、関数ie (for i nvoke(external) e xecutable)は、直接呼び出しの前にギャップを埋めます。 たとえば、次の呼び出しの代わりに:

# This command is currently broken, because the '{ "name": "foo" }' argument isn't properly passed.
curl.exe -u jdoe  'https://api.github.com/user/repos' -d '{ "name": "foo" }'

次を使用します。

# OK, thanks to `ie`
ie curl.exe -u jdoe  'https://api.github.com/user/repos' -d '{ "name": "foo" }'

Nativeモジュールには、 echoArgs.exeに似たもの、 dbeaDebug-ExecutableArguments )コマンドが付属しています。 Windowsでのサンプル出力:

# Note the missing first argument, the missing " chars., and the erroneous argument boundaries.
PS> dbea '' 'a&b' '3" of snow' 'Nat "King" Cole' 'c:\temp 1\' 'a \" b'
7 argument(s) received (enclosed in <...> for delineation):

  <a&b>
  <3 of snow Nat>
  <King>
  <Cole c:\temp>
  <1\ a>
  <">
  <b>

Command line (helper executable omitted):

  a&b 3" of snow "Nat "King" Cole" "c:\temp 1\\" "a \" b"

-UseIe-ie )スイッチを使用すると、 dbeaieを介して引数を渡すように指示できます。これは、問題が修正されたことを示しています。

# OK, thanks to -UseIe
PS> dbea -UseIe '' 'a&b' '3" of snow' 'Nat "King" Cole' 'c:\temp 1\' 'a \" b'
6 argument(s) received (enclosed in <...> for delineation):

  <>
  <a&b>
  <3" of snow>
  <Nat "King" Cole>
  <c:\temp 1\>
  <a \" b>

Command line (helper executable omitted):

  "" a&b "3\" of snow" "Nat \"King\" Cole" "c:\temp 1\\" "a \\\" b"

注:#1995が修正されると、 ieは不要になります。 上位互換性のために、 ieは、修正を検出して自動的に延期するように設計されています。 つまり、修正が行われると、 ieは回避策の適用を停止し、直接/ &呼び出しのように効果的に機能します。

ユースケース[直接の不正なWindows実行可能ファイル呼び出し]:

_Windowsのみ_で発生する2つの主な問題があります。

  • 最も広く使用されている規則とは異なる引用要件を持つ「不正な」実行可能ファイルを呼び出してmsiexec.exemsdeploy.exeprop="<value with spaces>"を正確にそのように引用する必要があります-_value_部分のすぐ周りの引用- "prop=<value with spaces>" -全体の引用引数-_should_は同等です(後者は、PowerShellが-当然のことながら-舞台裏で行うことです)。

  • スペースを含まないが、 &^|などのcmd.exeメタ文字を含む_an引数を使用して_バッチファイル_を呼び出しています。 例えば:

    • .\someBatchFile.cmd 'http://example.org/a&b'
    • PowerShellは-当然のことながら- http://example.org/a&b _unquoted_を渡します(空白が埋め込まれていないため)が、 cmd.exe -不当に-バッチファイルに渡された引数をリテラルとして受け入れるのではなくcmd.exe内部に適用されるのと同じ解析規則。

    • 注:バッチファイルを使用して機能を_直接_実装することはおそらく衰退していますが、バッチファイルaz.cmdとして実装されるAzureのaz CLIのように、それらを_CLIエントリポイント_として使用することは依然として非常に一般的です。

注: ie 、バッチファイル、 msiexec.exeおよびmsdeploy.exeこれらのシナリオを自動的に処理するため、_most_呼び出しの場合、追加の作業は必要あり

これを解決するには、次の2つの方法があります。

  • cmd.exe与えられた場合、コマンドラインの引数に独自の解釈を適用した後、指定されたとおりに引用符を保持します。Windowsでins呼び出しに委任できます。

    • ins '.\someBatchFile.cmd "http://example.org/a&b"'
    • _expandable_文字列を使用する場合、これにより、PowerShell値をコマンド文字列に埋め込むことができます。

      • $url = 'http://example.org/a&b'; ins ".\someBatchFile.cmd `"$url`""

  • または、現在の--%実装を使用しますが、その制限に注意してください。

    • .\someBatchFile.cmd --% "http://example.org/a&b"'
    • --%実装方法を考えると、PowerShell値を埋め込む唯一の方法は、厄介なことに_auxを定義することです。 環境変数_そして%...%構文でそれを参照します:

      • $env:url = 'http://example.org/a&b'; .\someBatchFile.cmd --% "%url%"


エラー処理

保留中のhttps://github.com/PowerShell/PowerShell-RFC/pull/88は、外部(ネイティブ)実行可能ファイルとのエラー処理の統合を改善します。

それまでの間、 Nativeモジュールには、ゼロ以外の終了コードをスクリプト終了エラーとして扱うアドホックオプトイン用の2つの機能が付属してい

  • ins-e / -ErrorOnFailureスイッチをサポートします。これは、ネイティブシェルの呼び出し後に$LASTEXITCODEがゼロ以外の場合にエラーをスローします。

  • ieeは、 ieラッパー関数であり、外部実行可能ファイルの呼び出し後に$LASTEXITCODEがゼロ以外の場合、同様にエラーをスローします。

モジュールに付属するコマンドには多くの微妙な点があります。
かなり広範なコメントベースのヘルプが、うまくいけばそれらを十分にカバーしています。

概念的な霧をクリアしたい場合は、ユースケースを別の方法で組み立てる必要があると思います。

すごい! 私が以前に投稿したのは、人々にもっと多くのより良いユースケースを作成することを考えさせるためだけでした。

以前に提案したものとは異なるinsInvoke-NativeShell )のいくつかの重要な側面を明確にする必要があります。 目的は、 bashの遍在性を説明し、プラットフォーム間で一貫したCLIを提供すること

  • Unixでは、Bashの普遍性を考慮して、 /bin/sh /bin/bashではなく-UseSh-sh /bin/shを使用することを選択できます。 -sh )( /bin/shは、 /bin/bashが存在しないという万が一の場合のフォールバックとしても機能します)。

    • 呼び出しフォームとプラットフォーム間で一貫したエクスペリエンスを実現するために、呼び出し名である$0を設定する機能を非表示にしました。 つまり、パススルー引数はすべて$1で始まります。これは、パイプラインからスクリプトをパイプ処理するときに引数が渡される方法、およびユーザーが期待するものと一致しています。
# Script as argument
PSonUnix> ins 'echo $# arguments; echo "[$1] [$2]"' one two
2 arguments
[one] [two]

# Script via pipeline; note the "-" to signal that the script is piped.
PSonUnix> 'echo $# arguments; echo "[$1] [$2]"' | ins - one two
2 arguments
[one] [two]

# As an aside: script as argument, with pipeline input *as data*:
PSonUnix> 'one', 'two' | ins 'cat -n'
     1  one
     2  two
  • Windowsの私には技術的な理由のために舞台裏での一時的な_batchの_ファイルタイプを使用する必要がありましたが、私は、バッチファイルの構文の使用は(とにかく最終的により良い選択だと思います%%iではなく%iforループ変数、 %%%としてエスケープする機能)。

    • バッチファイルを使用すると、Unixの場合と同様に、パススルー引数のサポートも有効になります。
# Script as argument
PSonWin> ins 'echo [%1] [%2]' one two
[one] [two]

# Script via pipeline; note the "-" to signal that the script is piped.
PSonWin> 'echo [%1] [%2]' | ins - one two
[one] [two]
このページは役に立ちましたか?
0 / 5 - 0 評価