Powershell: Hubungi operator asli

Dibuat pada 30 Jun 2020  ·  189Komentar  ·  Sumber: PowerShell/PowerShell

Pernyataan masalah

Saat ini, ada kasus di mana pemotongan dan penempelan baris perintah asli gagal berjalan seperti yang diharapkan di PowerShell. Ini mungkin karena penguraian kutipan yang salah yang dimaksudkan untuk diteruskan ke perintah asli atau penggunaan sintaks PowerShell yang tidak dimaksudkan untuk ditafsirkan sebagai PowerShell. PowerShell memiliki argumen khusus --% ketika digunakan dengan perintah asli memperlakukan argumen lainnya sebagai literal yang diteruskan ke perintah asli, tetapi memiliki beberapa masalah:

  1. Ini tidak dapat ditemukan, pengguna perlu mengetahui tentang parameter khusus ini sebelumnya
  2. | , && , dan || diutamakan, jadi: wsl --% ls | less akan mengeksekusi wsl ls dan menyalurkan hasilnya ke less berjalan di PowerShell daripada less berjalan di wsl
  3. Jika Anda memotong dan menempelkan baris perintah, Anda perlu mengedit baris untuk memasukkan --% ke awal
  4. Pada sistem Unix, args setelah -% diteruskan kata demi kata tanpa globbing di mana perintah asli pada Unix mengharapkan shell untuk melakukan globbing

Rincian implementasi teknis yang diusulkan

Proposal adalah untuk memperkenalkan operator --% (Panggilan Asli) baru.

Konten teks apa pun setelah operator ini akan memanggil "shell default" OS untuk dieksekusi. Di Windows, ini akan menjadi cmd.exe dan pada sistem berbasis Unix ini akan menjadi / bin / sh. Ini menyelesaikan masalah global pada sistem berbasis Unix, dan juga memungkinkan ekspansi %variable% pada Windows. Tidak seperti --% switch, ini juga berarti bahwa | , && , dan || diperlakukan sebagai bagian dari baris perintah asli.

Artinya, keduanya secara fungsional sama:

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

di mana $foo dan $PWD dievaluasi oleh shell dalam WSL. Perhatikan bahwa dalam contoh pertama, Anda harus tahu untuk melarikan diri && agar dijalankan dalam WSL dan bukan di dalam PowerShell.

Untuk menyalurkan keluaran dari eksekusi tersebut kembali ke PowerShell, pengguna diharuskan menyimpan hasil ke dalam variabel terlebih dahulu:

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

Perhatikan bahwa tidak seperti operator panggilan & , Anda tidak dapat menggunakan sintaks PowerShell apa pun, jadi:

--% $commandline

tidak akan menyelesaikan $commandline sebagai variabel terlebih dahulu oleh PowerShell, tetapi meneruskan $commandline ke shell default untuk memproses tidak terselesaikan.

Masalah potong & tempel diselesaikan hanya dengan menempelkan setelah --% diketik.

Contoh wsl di atas akan terlihat seperti ini:

--% wsl ls | less

dengan maksud agar seluruh baris tersebut dijalankan dalam instance WSL Linux.

Mudah ditemukan

Pengguna yang sudah terbiasa dengan --% karena pengalih dapat dengan mudah beralih menggunakan operator baru ini jika memungkinkan. Untuk pengguna baru, --% adalah unik sehingga mesin pencari dapat menemukannya dengan mudah terkait dengan PowerShell.

Pertimbangan Alternatif

&! dan &n telah diusulkan sebagai sigil, tetapi ada penolakan karena &! adalah operator yang valid dalam beberapa bahasa sehingga pencarian web untuk dokumentasi menjadi lebih sulit. Ada juga kekhawatiran apakah visual yang mirip dengan operator panggilan & akan membingungkan pengguna.

Ada pertanyaan tentang mendukung kelanjutan jalur saat menggunakan operator baru ini. Saya menyarankan agar kami tidak mendukungnya pada awalnya.

Solusi cmdlet, bukan solusi operator, diusulkan. Kami yakin ini tidak menyelesaikan masalah "potong & tempel" karena sekarang Anda perlu mengetahui cara meletakkan saluran dalam tanda kutip tunggal dan / atau melepaskan karakter khusus. Kami yakin cmdlet seperti pada Invoke-NativeCommand (kata benda yang akan ditentukan) akan berguna sebagai opsi tambahan daripada menggantikan kebutuhan akan operator.

Masalah terkait

Ini juga harus menyelesaikan masalah ini:

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

Committee-Reviewed Issue-Discussion Issue-Enhancement

Komentar yang paling membantu

Saya baru saja menerbitkan sebuah modul, Native , ( Install-Module Native -Scope CurrentUser ) yang saya undang untuk Anda semua untuk mencoba dan perintah siapa yang akan saya gunakan di bawah ; kasus penggunaan numerik yang direferensikan berasal dari komentar @rkeithhill di atas .

Jika kita ingin kabut konseptual menjadi jelas, saya pikir kita perlu membingkai kasus penggunaan secara berbeda.
_Tidak satupun dari mereka memerlukan perubahan apa pun dalam parsing_.

Kasus penggunaan [native-shell call]:

Anda ingin menjalankan perintah _individual_ (use case 1) atau seluruh _multi-command command line_ (use case 2) _written untuk platform-native shell_ (masalah ini):

  • Karena Anda menggunakan sintaks shell yang berbeda, Anda meneruskan perintah (baris) _sebagai satu string_ ke shell target, agar _it_ melakukan parsing; Interpolasi string PowerShell menawarkan kemampuan untuk menyematkan nilai PowerShell ke dalam string yang diteruskan (kasus penggunaan 2a).
  • ins ( Invoke-NativeShell ) mencakup kasus penggunaan ini.
# 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'

Sintaksis string di sini bukanlah yang paling nyaman (karena itu saran untuk mengimplementasikan varian sebaris - lihat # 13204), tetapi Anda tidak _have_ untuk menggunakannya; untuk perintah verbatim, Anda dapat menggunakan '...' , yang hanya membutuhkan _doubling_ tertanam ' , jika ada.

Selain itu, berikut ini pengganti yang wajar untuk "operator StackOverflow" :

Jika Anda menempatkan berikut PSReadLine handler kunci dalam Anda $PROFILE berkas, Anda akan dapat menggunakan Alt-v untuk perancah panggilan ke ins dengan kata demi kata di sini-string tempat teks papan klip saat ini ditempel.Masukkan mengirimkan panggilan.

# 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))
}

Kasus penggunaan [panggilan langsung yang dapat dijalankan]:

Anda ingin memanggil _single external executable_ menggunakan sintaks _PowerShell_, dengan _individual arguments_ (gunakan kasus 1a dan 3).

  • Ini adalah mandat inti dari shell apa pun, dan sangat penting agar shell berfungsi dengan baik.

    • Anda harus dapat mengandalkan PowerShell untuk dapat melewati argumen apa pun yang dihasilkan dari _its_ parsing _as-is_ ke target yang dapat dieksekusi. Saat ini bukan masalahnya - lihat # 1995 .
  • Ini mengharuskan Anda untuk memahami sintaks _PowerShell_ dan metakarakter mode argumen _its_.

    • Anda harus menyadari bahwa ` digunakan sebagai karakter escape dan untuk kelanjutan baris.
    • Anda perlu menyadari bahwa PowerShell memiliki karakter meta tambahan yang memerlukan kutipan / pelolosan untuk penggunaan verbatim; ini adalah (perhatikan bahwa @ hanya bermasalah sebagai karakter pertama argumen.):

      • untuk kerangka seperti POSIX (misalnya, Bash): @ { } ` (dan $ , jika Anda ingin mencegah ekspansi di muka oleh PowerShell)
      • untuk cmd.exe : ( ) @ { } # `
      • Satu ` satu printf %s `@list.txt ).

Sementara kita menunggu # 1995 diperbaiki, fungsi ie (untuk i nvoke (eksternal) e xecutable) mengisi celah tersebut, cukup dengan melakukan prapengiriman ke panggilan langsung; misalnya, alih-alih panggilan berikut:

# 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" }'

Anda akan menggunakan yang berikut ini:

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

Modul Native hadir dengan sesuatu yang mirip dengan echoArgs.exe , perintah dbea ( Debug-ExecutableArguments ); contoh keluaran di 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"

Dengan menggunakan sakelar -UseIe ( -ie ), Anda dapat memberi tahu dbea untuk meneruskan argumen melalui ie , yang menunjukkan bahwa ini memperbaiki masalah:

# 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"

Catatan: Setelah # 1995 diperbaiki, ie tidak lagi diperlukan; untuk kepentingan kompatibilitas ke depan, ie dirancang untuk mendeteksi dan secara otomatis menunda perbaikan; yaitu, setelah perbaikan dilakukan, ie akan berhenti menerapkan penyelesaiannya dan akan secara efektif bertindak seperti panggilan langsung / & .

Kasus penggunaan [panggilan eksekusi Windows nakal langsung]:

Ada dua masalah utama, yang muncul di _Windows only_:

  • Anda menggunakan executable "nakal" yang memiliki persyaratan kutipan yang berbeda dari konvensi yang paling banyak digunakan ; misal, msiexec.exe dan msdeploy.exe memerlukan prop="<value with spaces>" untuk dikutip dengan cara yang tepat - kutipan hanya di sekitar bagian _value_ - meskipun "prop=<value with spaces>" - mengutip dari keseluruhan argumen - _should_ setara (yang terakhir adalah apa yang PowerShell - dapat dibenarkan - lakukan di belakang layar).

  • Anda memanggil _a file batch_ dengan _an argumen yang tidak berisi spasi, tetapi berisi cmd.exe metacharacters_ seperti & , ^ , atau | ; misalnya:

    • .\someBatchFile.cmd 'http://example.org/a&b'
    • PowerShell - justifiably - melewati http://example.org/a&b _unquoted_ (karena tidak ada spasi yang disematkan), tetapi ini merusak pemanggilan file batch, karena cmd.exe - tidak masuk akal - subjek argumen yang diteruskan ke file batch ke aturan penguraian yang sama yang akan diterapkan di dalam cmd.exe daripada menerimanya sebagai literal.

    • Catatan: Meskipun menggunakan file batch untuk _directly_ mengimplementasikan fungsionalitas mungkin berkurang, menggunakannya sebagai titik masuk _CLI_ masih sangat umum, seperti Azure az CLI, yang diimplementasikan sebagai file batch az.cmd .

Catatan: ie secara otomatis menangani skenario ini untuk file batch dan untuk msiexec.exe dan msdeploy.exe , jadi untuk panggilan _most_ tidak diperlukan upaya ekstra ; bagaimanapun, tidak mungkin untuk mengantisipasi _all_ executable "nakal".

Ada dua cara untuk mengatasinya:

  • Mengingat bahwa cmd.exe , setelah menerapkan interpretasinya sendiri ke argumen pada baris perintah, _does_ mempertahankan kutipan seperti yang ditentukan, Anda dapat mendelegasikan ke panggilan ins di Windows:

    • ins '.\someBatchFile.cmd "http://example.org/a&b"'
    • Jika Anda menggunakan string _expandable_, ini memungkinkan Anda untuk menyematkan nilai PowerShell ke dalam string perintah.

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

  • Alternatifnya, gunakan implementasi --% , tetapi waspadalah terhadap batasannya:

    • .\someBatchFile.cmd --% "http://example.org/a&b"'
    • Mengingat bagaimana --% diimplementasikan, satu-satunya cara untuk menanamkan nilai PowerShell adalah - dengan canggung - mendefinisikan _aux. variabel lingkungan_ dan referensikan dengan sintaks %...% :

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


Penanganan kesalahan

Https://github.com/PowerShell/PowerShell-RFC/pull/88 yang tertunda akan membawa integrasi penanganan kesalahan yang lebih baik dengan executable eksternal (asli).

Sementara itu, modul Native dikirimkan dengan dua fitur ad-hoc opt-in untuk memperlakukan kode keluar bukan nol sebagai kesalahan penghentian skrip :

  • ins mendukung saklar -e / -ErrorOnFailure , yang akan memunculkan kesalahan jika $LASTEXITCODE bukan nol setelah panggilan ke shell asli.

  • iee adalah fungsi pembungkus untuk ie yang secara analogis memunculkan kesalahan jika $LASTEXITCODE bukan nol setelah panggilan ke eksekusi eksternal.

Ada banyak seluk-beluk perintah yang dikirimkan bersama modul.
Bantuan berbasis komentar yang cukup luas semoga cukup mencakupnya.

Semua 189 komentar

Saya suka idenya dan merasa berguna, tetapi menurut saya itu akan jauh lebih berguna (saya berpikir secara khusus dalam kasus DSL) jika saya bisa mendapatkan ekspansi string tunggal. Jadi jika saya telah membangun string yang kompatibel dengan cmd.exe di PS saya, saya memiliki cara untuk membuat string kata demi kata ke cmd.exe. Mungkin

&n -command $string

Itu juga berpotensi memungkinkan saya menentukan penerjemah saya:

&n -shell /bin/sh -command $string
atau
&n -shell cmd.exe -command $string

dalam istilah nama / operator, adalah "&!" digunakan? Itu memiliki kesamaan dengan shbang ("#!").

$! adalah saran yang bagus!

Shell dapat ditentukan hanya dengan menetapkannya sebagai perintah:

&! /bin/sh -c blah

Ekspansi $var menciptakan masalah karena $ mungkin perlu literal untuk diteruskan ke perintah / shell asli. Salah satu masalah yang coba dihindari ini adalah ketika orang perlu mencari cara untuk melarikan diri dari segalanya dengan benar. Jika Anda membutuhkan ekspansi variabel, Anda selalu dapat melakukan:

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

Namun, dalam kasus di mana Anda ingin mencampur PowerShell dengan perintah asli, mungkin yang terbaik adalah menggunakan sintaks saat ini dan hanya menyadari apa yang perlu diloloskan dengan benar karena saya akan mempertimbangkan penggunaan lanjutan itu.

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

Saya tidak percaya Anda baru saja menyarankan IEX. :-)

@essentialexch ada beberapa waktu yang sesuai :)

Perhatikan bahwa dalam contoh, ekspektasinya adalah pengguna memvalidasi konten $mycommand sebelum mengeksekusi!

Tulisan yang bagus dan solusi untuk masalah seperti yang Anda jelaskan pasti dibutuhkan.
Saya sendiri tidak tahu tentang --% dan sayangnya tidak pernah melihatnya. Oleh karena itu operator &n diusulkan mungkin mengalami masalah serupa untuk dapat ditemukan dan tidak wajar bagi saya untuk menggabungkan simbol dengan karakter (dan ini mengingatkan saya pada% f dalam pernyataan C printf). Karena ini adalah perubahan yang merusak Apakah ada alasan mengapa tidak bisa misalnya && ?
Mungkin akan lebih intuitif bagi saya untuk menggunakan sesuatu seperti tanda kurung (atau tanda kurung ganda?) Untuk menandai area yang ingin Anda eksekusi. Contoh: & [ wsl ls ] | less

Saya setuju &! adalah cara yang lebih intuitif untuk mereka yang berasal dari shell lain, namun di super-duper-linter saya biasanya menjalankan perintah asli dengan membangun array parameter dan kemudian memerciknya ke perintah.

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

Jadi ini adalah cara terbaik dalam hal bersyarat dan yang lainnya bagi saya

@bergmeister Awalnya saya mengira && secara visual mirip dengan & yang banyak orang kenal sekarang. Namun, && menjadi operator rantai pipa dapat menyebabkan kebingungan tentang apa yang seharusnya dilakukannya. Saya menyukai saran &! saat ini.

@JustinGrote , tidak ada alasan untuk tidak terus menggunakan itu. sintaks &! benar-benar untuk kasus di mana Anda hanya ingin memotong dan menempel atau memiliki beberapa argumen yang bertentangan dengan sintaks PowerShell dan tidak ingin atau tidak tahu cara keluar dengan benar

Ya ampun, saya ingat pernah berdiskusi dengan Bruce dan Jason tentang ini satu dekade lalu. Perasaan saya adalah menemukan operator lain sepertinya tidak perlu di sini. Saya tahu bahwa beberapa orang di utas ini belum pernah mendengar tentang --% tetapi saya akan bertaruh daripada yang Anda pikirkan. Ada apa dengan:

# 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"

Mengapa tidak ada yang menyarankan ini? Secara logis konsisten dengan penggunaan --% tempat lain untuk mengatakan "segala sesuatu setelah ini akan dilalui tanpa perlakuan khusus PowerShell."

@oising baik untuk satu, perintah itu tidak berfungsi karena Anda harus memulainya dengan perintah yang ingin Anda jalankan, apakah Anda menyarankan untuk menambahkan fungsionalitas?
image

Ini seperti melakukan apa yang diharapkan:
function Invoke-LiteralCommand ($command) {Invoke-Expression "& $command --% $args"}

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

@JustinGrote Ya, saya tahu itu tidak berfungsi sekarang :) Saya menyarankan bahwa _instead_ dari &n atau &! atau apa pun yang sedang dibicarakan. Ini hanya lebih masuk akal bagi saya: & adalah panggilan dan --% menekan parsing PowerShell; bersama-sama mereka koheren dan lebih mudah ditemukan daripada menambahkan sesuatu yang baru. Saya tidak suka gagasan memiliki operator "panggilan" dan "panggilan asli".

Saya telah memperluas contoh saya untuk menunjukkan perbedaannya.

@oising Saya akan senang dengan itu melalui operator baru, meskipun itu banyak mengetik tumpul untuk "pengguna PowerShell baru yang tahu bash" yang saya anggap ini akan dimaksudkan untuk.

@oising Saya akan senang dengan itu melalui operator baru, meskipun itu banyak mengetik tumpul untuk "pengguna PowerShell baru yang tahu bash" yang saya anggap ini akan dimaksudkan untuk.

Tidak semuanya. Ini untuk pengguna PowerShell yang tidak memahami aturan kutipan kompleks antara PowerShell / cmd.exe / bash. Seperti judul terbitan mengatakan "call native", untuk memanggil executable asli.

@oising Saya akan senang dengan itu melalui operator baru, meskipun itu banyak mengetik tumpul untuk "pengguna PowerShell baru yang tahu bash" yang saya anggap ini akan dimaksudkan untuk.

Tidak semuanya. Ini untuk pengguna PowerShell yang tidak memahami aturan kutipan kompleks antara PowerShell / cmd.exe / bash. Seperti judul terbitan mengatakan "call native", untuk memanggil executable asli.

Benar, atau bagi kita yang lebih suka tidak memikirkannya sama sekali.

Ya saya dengan @oising. Konsep ini ada, sayangnya tidak cukup. Jika kita akan menerapkan sesuatu yang benar-benar baru, lebih baik kita menghentikan / menghapus sintaks lama.

Saya merasa seringkali ide-ide ini disuarakan, tidak cukup bobot diberikan pada target demografis mereka yang sebenarnya. Jika pengguna _sudah_ berjuang untuk menemukan metode yang ada, dan menemukan metode yang ada kurang saat ditemukan, itu panggilan untuk a) meningkatkan dokumentasi, dan b) meningkatkan fungsionalitas aktual dari operator yang ada.

Sebagai gantinya kami mendapatkan opsi aneh c) yang seharusnya entah bagaimana mengatasi masalah masa lalu sambil memperkenalkan operator namun _another_ yang mengandalkan dokumentasi yang sudah tidak cukup dapat diakses bagi pengguna untuk menemukannya secara alami.

Saya setuju bahwa pesan kesalahan dan / atau sistem saran harus digunakan untuk membantu memperkenalkan konsep ini. Saya tidak setuju bahwa kita membutuhkan yang ketiga? keempat? kelima? (Saya benar-benar kehilangan hitungan, seseorang membantu saya di sini) cara untuk menjalankan perintah. Metode yang ada tidak mencukupi - itu berarti kita harus _meningkatkan_ mereka, tidak meninggalkannya seperti jaring laba-laba untuk membingungkan pengguna lebih jauh ketika mereka mulai menggalinya.

Pertanyaan pertama yang cenderung saya dapatkan ketika orang menyadari ada 5 cara untuk melakukan sesuatu adalah "mengapa ada 2-3 cara yang benar-benar melakukan hal yang sama tetapi tidak berhasil juga", dan jawaban saya adalah seperti biasanya - - tim PS _way_ terlalu fokus untuk memastikan segala sesuatu dari dekade terakhir ++ masih berfungsi, ketika mencoba menambah / meningkatkan fungsionalitas. Di sini kita melihatnya lagi, kita memiliki implementasi yang ada tetapi tidak cukup yang perlu direvisi dan ditingkatkan, dan solusi yang diusulkan adalah untuk semakin memperkeruh kolam dengan menambahkan implementasi lain yang berpotensi tidak lengkap.

Kita harus menyelesaikan apa yang kita mulai, bukan memulai implementasi lain lagi, IMO.

Saya percaya jika kita akan menggunakan & untuk lebih dari beberapa kasus penggunaan unik, kita harus mulai berpikir untuk menjadikannya sebagai kata kerja atau melihat standarisasi di seluruh bahasa.

Hal terakhir yang saya inginkan adalah kebingungan tentang apa & yang harus dilakukan. Secara keseluruhan.

Saya akan mempertimbangkan 3 skenario:

  1. Ekspansi penuh - perilaku PowerShell saat ini.
  2. Literal penuh - yang diusulkan di OP.
  3. Perluasan sebagian - wsl ls $path masih berfungsi

Saya ingin tahu di mana komentar @ mklement0 ? :-)

Saat mulai membaca utas ini, saya berpikir; ide yang hebat! Tetapi setelah membaca komentar, saya mulai berpikir. Saya selalu menemukan & perintah 'bukan standar PS yang layak "dan sesuatu yang mengingatkan saya tentang' PERL hari '(ugh). Memperkenalkan perintah PS non-standar lainnya (bukan kata benda-kata kerja) tidak akan membantu. Tentu saja bukan mereka yang kurang paham PS.

Saya juga tidak tahu tentang parameter -%. Saya menggunakan prinsip yang sama dengan @JustinGrote sebagai solusi.

Memotong / menempel perintah ke shell PS tidak pernah menjadi 'hal' utama saya.
Bukankah lebih baik kita mengganti perintah asli itu dengan PowerShell?
Buat jalur untuk mengganti cmd.exe seluruhnya ...

Saya memilih untuk mengeksplorasi meningkatkan perintah yang ada. Dan - memang - meningkatkan beberapa dokumentasi tentang -% dan & penggunaan

@iSazonov kasus penggunaan yang diusulkan @ SteveL-MSFT adalah skenario 'potong tempel'. Ekspansi parsial akan membuat segalanya lebih sulit menurut saya (di sisi AST)

Seketika dari "#!" lalu "!#". Menyukai "&!".

Kita mungkin bisa melihat menambahkan akselerator token ke pemanggilan fungsi di tokenizer. Ini akan memungkinkan penggunaan berikut ini.

Iex -l
Atau Invoke-Expression -literal yang berhenti parsing sebelum melewati.

Saya merasa menambahkan lebih banyak token unik pada tingkat penguraian membuat penghalang untuk masuk naik dan kemampuan untuk dapat ditemukan fitur ini turun.

Dapatkan-Bantuan & misalnya tidak muncul dengan apa pun. Dan kita harus mencarinya di about_Operators.

Namun ada kasus unik untuk call_operator yang tidak didokumentasikan.
& modulename {command}
memungkinkan Anda untuk masuk ke dalam modul. Dan saya yakin masih ada lagi. Tetapi kemampuan untuk dapat ditemukan di sana sangat rendah sehingga menjadi sulit untuk ditemukan dalam dokumentasi asli. Dan komunitas tahu tentang itu hanya melalui JSnover dan ceramah yang dia berikan menunjukkan hal-hal keren kepada kami.

Saya percaya apa pun yang diputuskan, perlu sepenuhnya mempertimbangkan seberapa mudah ditemukan "fitur" ini, dari perspektif pengguna baru dan perlu diingat bahwa pengguna baru akan mencoba menggunakan ini di Powershell 5 bukan tanpa mengetahui fitur baru untuk inti pwsh jika kemampuan untuk ditemukan terlalu rendah.

Saya ingin kami mengubah perilaku yang ada, tetapi mengubah API mendasar di PowerShell hanya akan merusak banyak hal. Kami mungkin dapat mempertimbangkan untuk bermigrasi dengan konfigurasi.

Memecah hal-hal secara lebih langsung mungkin pernah mungkin dilakukan sebelum PS 6 menjadi GA, tetapi sejujurnya, itu akan menjadi ancaman serius bagi kompatibilitas ke belakang (tidak seperti fungsi Python print() ).

Dalam hal menyampaikan argumen ke subproses, saya pikir baik doa sinkron maupun permintaan Start-Process sudah memiliki masalah bertingkat membahas perombakan, dan perasaan saya adalah bahwa keduanya perlu berinvestasi sekaligus untuk konsistensi. Start-Process secara khusus perlu memperbarui dukungannya untuk meneruskan berbagai argumen.

Untuk pemanggilan sinkron dengan pengoperan argumen cmdline, saya melihat empat jenis pengoperan argumen mungkin:

  • Perilaku saat ini, yang akan menjadi warisan, yang tunduk pada CommandLineToArgvW di Windows dan memiliki hasil yang tidak diharapkan
  • Perilaku default, yang harus melewatkan argumen dengan nilai ekspresinya tetapi menerapkan aturan token bareword biasa, sehingga hal-hal seperti > dan | perintah terpisah. Dalam mode ini, nilai yang diambil subproses dari ekspresi harus apa yang ditampilkan oleh Write-Host $val
  • Perilaku kata demi kata, di mana semua token diinterpretasikan sebagai string bareword hingga token escape terlihat. Inilah yang seharusnya dilakukan --% hari ini, tetapi idealnya hanya memiliki satu token akhir yang dapat disematkan pada baris yang sama seperti --% ... %--
  • Perilaku readline Bash, di mana logika pelolosan alternatif berorientasi-sh diterapkan, memungkinkan kompatibilitas yang lebih sederhana

Saya pikir perilaku pertama harus dihapus secara bertahap dengan memperkenalkan yang kedua sebagai fitur eksperimental dan kemudian menukarnya.

Perilaku kedua dan ketiga dapat memiliki tanda-tanda mereka sendiri seperti &! dan &# atau mungkin +% ... -% atau semacamnya. Tetapi untuk mode verbatim, saya pikir aspek penting akan menyederhanakan token escape sehingga lebih banyak token diambil kata demi kata. Mirip dengan heredoc.

Jika permintaan hanya untuk mengatasi skenario salin-tempel seperti "Konten teks apa pun setelah operator ini akan memanggil ke" shell default "OS untuk dijalankan." mengapa tidak mengatakan ini secara eksplisit dengan shell ?
`` powerhell
PS> shell wsl ls | kurang
PS> (shell wsl ls * .txt) | Select-String Halo

Ini lebih dapat ditemukan dan dibaca daripada operator kriptik dalam gaya Forth / APL.

Saya benar-benar tidak melihat bagaimana ini akan menyelesaikan # 1995: Lihat https://github.com/PowerShell/PowerShell/issues/1995#issuecomment -653174261

Juga, masalah dengan WSL adalah masalah perilaku wsl.exe (lihat https://github.com/PowerShell/PowerShell/issues/12975#issuecomment-650353021) bukan dari PowerShell.
(Oke, ada masalah dengan PowerShell, tapi itu # 1995)

Oh, dan bukankah ini hampir merupakan duplikat dari https://github.com/PowerShell/PowerShell/issues/12975 ? Karena saya pada dasarnya dapat mengulangi, apa yang saya sebutkan di sana:

@tokopedia
Masalahnya adalah kurangnya kemampuan untuk membatasi sebagian dari baris perintah yang akan diteruskan secara varbatim ke perintah / skrip penerima adalah sesuatu yang membuat pengguna naik sepanjang waktu.
Apa yang Anda maksud dengan "bagian dari baris perintah yang akan diteruskan secara varbatim"? Maksud Anda 1. meneruskan beberapa urutan karakter kata demi kata ke yang disebut dapat dieksekusi, sehingga yang disebut dapat dieksekusi memiliki urutan karakter ini dalam satu elemen dari array argumennya (misalnya karakter tersebut kemudian tersedia di `argv [1]` di [main ] (https://docs.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?view=vs-2019#command-line-arguments)) Atau yang Anda maksud 2. menyisipkan beberapa urutan karakter kata demi kata ke dalam parameter [`lpCommandLine` dari` CreateProcess`] (https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw#parameters) - - Jika maksud Anda (1.), maka pada dasarnya ini sudah berfungsi:
PS /home/User> /bin/echo 'cd / && ls . | cowsay'
cd / && ls . | cowsay
PS /home/User>
(Kecuali untuk masalah kutipan yang disematkan seperti yang dibahas di https://github.com/PowerShell/PowerShell/issues/1995) Orang dapat berargumen, bahwa menambahkan satu baris-di sini-string akan meningkatkan beberapa kasus penggunaan, tetapi saya pikir, bukan itu inti dari masalah ini. Karena ini sudah bekerja kurang lebih, saya berasumsi, yang Anda maksud (2.) --- Jika yang Anda maksud (2.), izinkan saya menyatakan pendapat saya tentang itu dengan cara yang agak dramatis: Tolong tolong jangan menambahkan sintaks khusus untuk ini. Ini pada dasarnya adalah apa yang `-%` coba lakukan, yang seharusnya tidak pernah diterapkan. Mengapa saya sangat menentang ini? 1. Ini adalah masalah khusus Windows, jadi menambahkan sintaks berarti bahwa PowerShell di Windows memiliki sintaks yang berbeda dengan di Linux. (Atau sintaks akan didukung tetapi sama sekali tidak berarti, karena saat ini kasus untuk `-%`) 2. Jika shell baris perintah utama pada Windows yang diterbitkan oleh Microsoft menambahkan fitur kelas satu (melalui sintaks khusus yang bertentangan dengan via a cmdlet) untuk memanggil file yang dapat dieksekusi yang tidak mengikuti [aturan penguraian baris perintah] (https://docs.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?view=vs -2019 # parsing-c-command-line-arguments) (jika alat mengikuti aturan umum, Anda tidak perlu (2.), Anda biasanya dapat menggunakan (1.)) dengan lebih baik, maka itu mendorong penulis baris perintah alat, untuk tidak mengikuti aturan ini, yang hanya memperburuk ["anarki baris perintah Windows"] (https://stackoverflow.com/a/4094897/2770331). Semakin sedikit orang yang mengikuti aturan umum, semakin sulit untuk secara terprogram memanggil executable eksternal atau secara umum menulis kode lintas platform, jadi menurut saya, pembuat program harus didorong untuk mengikuti aturan umum tersebut. 3. Saya sangat meragukan, bahwa ini adalah kasus penggunaan yang umum> Dan ini bukan hanya masalah yang mempengaruhi WSL: Ini juga mempengaruhi pemanggilan baris perintah wt Terminal Windows, dan banyak alat lainnya. Bisakah Anda menambahkan beberapa contoh, di mana masalah seperti itu terjadi? Karena dalam kasus WSL, saya akan mengatakan bahwa parsing WSL dari baris perintah hanya [rusak] (https://github.com/Microsoft/WSL/issues/1746) (masalahnya adalah tentang `bash.exe` tetapi situasinya secara default tidak lebih baik dengan `wsl.exe`) dalam kasus default - saya akan mempertimbangkan setiap alat, yang tidak mengikuti [aturan penguraian baris perintah] (https://docs.microsoft.com/en-us/ cpp / cpp / main-function-command-line-args? view = vs-2019 # parsing-c-command-line-arguments) rusak, tetapi perilaku default WSL adalah IMHO bahkan tidak didokumentasikan dengan benar ... Saya mengatakan "default "perilaku` wsl.exe` rusak - saat menulis tanggapan ini, saya perhatikan, bahwa `wsl.exe` sebenarnya tampak berperilaku seperti yang diharapkan, saat menggunakan` -e`:
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:\>
Jadi satu-satunya hal yang hilang untuk usecase eksplisit ini adalah IMO parameter ke `wsl.exe` untuk memanggil shell default dengan argumen baris perintah yang diuraikan seperti pada exe normal lainnya.

Satu-satunya hal mengenai "bagian dari baris perintah yang akan diteruskan varbatim ke perintah / skrip penerima", yang akan ditingkatkan dengan operator ini akan menjadi makna (2.) di atas, dan seperti yang disebutkan, saya pikir mengembangkan ke arah itu adalah buruk.

Jika yang ingin Anda lakukan hanyalah pintasan, salin & tempel baris perintah yang ada, mengapa Anda tidak menambahkan cmdlet (mis. Invoke-Shell , yang memanggil bash -c di linux dan cmd /c di jendela?
Maka Anda bisa melakukannya

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

Jika harus satu baris, tambahkan sintaks satu baris-di sini-string, tetapi tolong jangan menerapkan operator khusus, yang tidak dapat ditemukan dengan benar dan hanya memperumit segalanya.

Dan tolong jangan tinggalkan # 1995 untuk ini!

+10 poin untuk menggunakan kata "sigil".

Hal yang menyenangkan tentang &! versus shell adalah bahwa "shell" adalah kata bahasa Inggris yang umum, oleh karena itu orang mungkin memiliki perintah bernama shell. (Sebenarnya, saya memiliki fungsi bernama "shell" dan fungsi bernama "n" (karena itu saya tidak suka &n ).)

@oising : & --% bagus, kecuali salah satu tujuan yang dinyatakan dari fitur yang diusulkan adalah untuk mengartikan bahwa | menjadi sesuatu yang diteruskan ke shell asli; bukan sesuatu yang membawa Anda kembali ke parsing PowerShell. Dan jika kita membuat prioritas pipeline berbeda untuk & --% daripada untuk foo $blah --% more args , saya akan menemukan itu membingungkan ... bagaimana jika Anda melakukan & $foo --% more args | blah ? Jadi menurut pendapat saya, usulan &! cukup berbeda sehingga memerlukan operator yang berbeda. (Dengan kata lain: fungsionalitas yang diusulkan terkait tetapi berbeda dari menggabungkan & dan --% .)

Fitur ini lebih dari sekadar untuk "pengguna PowerShell baru yang mengetahui bash" dan "pengguna yang tidak mengetahui semua aturan kutipan / pelolosan yang rumit". Ini juga untuk sebagian besar pengguna ahli, yang hanya ingin menyalin / menempelkan perintah dari StackOverflow tanpa harus masuk dan mengutak-atik semuanya. Ini cukup sering terjadi pada saya - produk yang saya kerjakan memiliki banyak dokumentasi tentang bagaimana melakukan sesuatu, dan lingua franca adalah perintah cmd.exe - jadi saya harus pergi dan berurusan dengan memperbaiki% VARIABLE_REFERENCES% dll .; akan jauh lebih baik jika mengetik &! dan kemudian menempelkannya. Sebenarnya jika ini diterapkan, saya mungkin akan menyebutnya sebagai "operator StackOverflow". : D

@ vexx32 : Ini bukan operator panggilan "satu dering untuk mengatur semuanya"; hanyalah alat lain di kotak alat untuk mengatasi masalah umum. Saya tidak berpikir kita harus menyingkirkan alat yang ada untuk memberi ruang bagi yang satu ini; mereka melakukan hal yang berbeda. Saya memahami bahwa pengguna baru mungkin merasa kewalahan saat kotak peralatan memiliki palu, obeng, bor, bor tumbukan, dan pistol paku ... tetapi terlepas dari kenyataan bahwa mereka semua untuk "menusuk benda pokey melalui satu atau lebih lainnya hal-hal ", mereka sangat berharga bagi seorang profesional; semua digunakan dalam situasi yang berbeda (meskipun terkait).

@ TSlivede : Saya setuju bahwa # 1995 itu terpisah. Tetapi saya tidak setuju dengan "Ini adalah masalah khusus Windows": menyalin dan menempelkan perintah khusus platform dari StackOverflow berlaku sama untuk OS apa pun. (Sebenarnya, ini akan sangat membantu bagi banyak orang seperti saya yang lebih kuat di satu platform daripada yang lain - Saya lebih mahir dengan teknologi Windows, jadi ketika di Linux saya cenderung melakukan BANYAK menyalin dan menempel dari SO.)

Baik melalui operator baru &! atau perintah Invoke-Shell , saya tidak memiliki perasaan yang kuat seperti yang lain ... Saya bersimpati dengan orang-orang yang mengeluh bahwa operator sulit dicari, dll. Tetapi Saya sangat suka singkatnya &! .

@jazzdelightsme ini bukan "alat lain di kotak peralatan", melainkan "lampiran obeng lain yang sangat spesifik untuk obeng yang sudah memiliki sekitar 3-5 obeng yang saat ini sudah _okay_ dan dapat ditingkatkan" menurut pendapat saya.

@jazzdelightsme Bagian "hanya Windows" mungkin lebih terkait dengan masalah di mana saya awalnya memposting pernyataan itu - ya OK, ini bukan duplikat persis dari masalah itu.

Jika # 1995 tidak ditinggalkan dan fitur yang diminta di sini tidak diselesaikan melalui Sintaks khusus tetapi melalui commandlet (atau mungkin Sintaks baru untuk string satu baris di sini yang berfungsi di mana saja tidak hanya untuk kasus khusus ini) maka saya sebenarnya mendukung menambahkan fungsi ini. (Atau mungkin tidak "mendukung" tetapi "Ini benar-benar dapat diterima oleh saya")

Ide lain: Jika masalah ini sebenarnya tentang salin & tempel perintah lengkap yang dimaksudkan untuk shell asli, mungkin PsReadLine dapat menambahkan fitur untuk menerjemahkan perintah secara kasar dari gaya bash atau cmd ke PowerShell. Terjemahan dapat dipicu oleh kombinasi tombol khusus atau secara otomatis jika terjadi kesalahan penguraian saat mencoba menjalankan perintah.

Ini akan memiliki keuntungan tambahan dalam mengajari pengguna Syntax PowerShell.

Mengenai kemampuan untuk dapat ditemukan: PsReadLine selalu dapat menampilkan pesan dalam waktu singkat bahwa kombinasi tombol tertentu dapat digunakan, setiap kali konten yang salah secara sintaksis (yang akan berlaku setelah terjemahan) ditempel.

Tapi saya bisa mengerti jika ini hanya sedikit rumit untuk disadari.

@jazzdelightsme apakah Anda berbicara dengan @joeyaiello? Kupikir hanya dia yang menyebutnya StackOverflow operator yang membuatku ngeri padahal itu benar

@ SteveL-MSFT Tidak, saya tidak berbicara dengan siapa pun tentang ini; Saya tiba di "operator StackOverflow" secara mandiri. xD

@jodohgratis

... kecuali salah satu tujuan tersurat dari fitur yang diusulkan adalah bahwa | menjadi sesuatu yang diteruskan ke shell asli; bukan sesuatu yang membawa Anda kembali ke parsing PowerShell.

Saya tidak yakin Anda telah memahami saran saya; apa yang Anda katakan adalah _ tepatnya_ apa yang saya katakan. Izinkan saya lebih bertele-tele dengan beberapa petunjuk yang dikapitalisasi secara strategis: 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)
@'

Apa yang kulewatkan di sini? Jika pipa muncul setelah --% itu hanya karakter bodoh lainnya: sebuah argumen. Tidak ada mengutak-atik prioritas operator. Jika terdapat dalam pipeline atau subekspresi bersarang, mulailah mengurai PowerShell lagi.

bagaimana jika Anda melakukan & $ foo -% more args | bla?

Nah, itu akan mencoba untuk mengeksekusi argumen di $foo dan meneruskan "more" , "args" , "|" dan "blah" untuk diperlakukan sebagai milik apapun. di $foo keinginan. Aturannya tampak cukup sederhana bagi saya, tetapi saya harus menggunakan PowerShell / Monad sejak lama. Ini bukan perubahan besar menjadi & karena & $foo --% ... memperlakukan --% seperti argumen lainnya. Jadi, kecuali kita telah menggunakan sigil ini di tempat lain dengan jahat, kita seharusnya aman.

Pikiran?

Saya membuat beberapa pengeditan di atas, untuk mencakup evaluasi garis parsial, evaluasi multiline, dan pemosisian variabel --% . Semua tanpa memperkenalkan sigil baru, operator, atau sintaks aneh. Saya pikir itu mencakupnya. Satu-satunya hal adalah: Bisakah pengurai menanganinya? Bagaimana menurut Anda @lzybkr @JamesWTruher @BrucePay ?

Dengar, dengar, @TSlivede.

Maafkan saya karena terus terang, tetapi kita telah membicarakan masalah ini untuk waktu yang sangat lama:

Apa yang diusulkan masalah ini sama dengan pemikiran magis:
Hal ini terkait dengan "simbol stop-parsing" yang bernasib malang, yang secara inheren bermasalah, --% , yang dalam bentuknya saat ini adalah penggunaan terbatas _ pada Windows_ (lihat https://github.com/MicrosoftDocs/PowerShell- Docs / issues / 6149) dan hampir tidak berguna di platform serupa _Unix_ (lihat https://github.com/MicrosoftDocs/PowerShell-Docs/issues/4963).
--% semestinya tidak pernah diterapkan, dan proposal ini juga tidak boleh diterapkan seperti yang disajikan.

Pemikiran magis adalah penggabungan dua gagasan yang secara konseptual kacau:

  • (a) "Saya ingin meneruskan token yang dipisahkan spasi ke beberapa program eksternal, mengizinkan bareword apa pun, tanpa perlu khawatir tentang metakarakter shell seperti & atau | ." - lihat https://github.com/PowerShell/PowerShell/issues/12975#issuecomment -646276628

    • Tentu saja, fitur seperti itu bertentangan dengan penggunaan perintah semacam itu _sebagai bagian dari pipeline_ atau dengan operator _pipeline-chaining_ ( && dan || ), dan juga menempatkan perintah tambahan di baris yang sama, setelah ; - dan, paling tidak, bisa menggunakan variabel _PowerShell dan ekspresi_ apa pun di baris perintah.
  • (b) "Saya ingin baris perintah saya diperlakukan seperti yang biasa saya _dari shell yang biasanya saya gunakan_ (atau shell tempat baris perintah aslinya ditulis)", yang, tentu saja, _adalah_ tunduk pada penggunaan karakter tanpa tanda kutip seperti & atau | ditafsirkan sebagai karakter meta dan oleh karena itu memiliki arti _syntactic_.

    • Contoh kasus: baik cmd atau /bin/sh (atau shell seperti POSIX seperti bash ) tidak akan menerima wsl ls | less dengan cara yang melewati ls , | , dan less _verbatim_ hingga wsl - mereka semua akan menafsirkan _unquoted_ | sebagai simbol _their_ pipe.

Ide-ide ini bertentangan satu sama lain, dan membutuhkan solusi yang berbeda - keduanya tidak memerlukan sintaks khusus:

  • Solusi untuk (a) adalah dengan _abandon_ gagasan dan sebagai gantinya menggunakan sintaks _PowerShell sendiri yang ada_ untuk memastikan bahwa karakter meta digunakan _verbatim_ - yang selalu memerlukan _quoting_ atau _escaping_ ,:

    • Salah satu: kutipan barewords (token tidak diapit tanda kutip) yang berisi karakter meta _secara keseluruhan_: wsl ls '|' less
    • Atau: ` -escape metacharacters _individually_ in barewords: wsl ls `| less
    • Atau: gunakan _array [variabel] _ untuk meneruskan argumen _verbatim_: $wslArgs = 'ls', '|', 'less'; wsl $wslArgs
    • Tentu saja, # 1995 mendemonstrasikan bahwa, sayangnya, pendekatan ini telah dan selalu gagal ketika berhubungan dengan argumen yang telah _embedded_ " _ketika memanggil program eksternal_ - _ini perlu ditangani_: lihat di bawah.
  • Solusi untuk (b) adalah dengan benar-benar _memanggil shell yang biasanya saya gunakan_, meneruskan baris perintah _sebagai string_ tunggal_.

    • Seperti yang disarankan @TSlivede , Invoke-Shell cmdlet yang Anda berikan baris perintah _sebagai satu string_ dan yang memanggil _platform-native shell_ adalah solusinya - dan kami sudah memiliki sintaks untuk string verbatim ( '...' atau varian string di sini, @'<newline>...<newline>'@
    • Rekomendasi saya adalah menyebutnya Invoke-NativeShell , dan memanggil /bin/sh - bukan bash - pada platform mirip Unix.

      • Selain itu, saya sarankan untuk mendefinisikan ins sebagai alias yang ringkas.

    • Pendekatan ini menyelesaikan semua masalah konseptual dengan --% dan dengan proposal yang ada:

      • Itu membuatnya sangat jelas di mana perintah yang diteruskan ke shell asli berakhir (berdasarkan menjadi _a string tunggal_), dan ini memungkinkan menggunakan panggilan Invoke-NativeShell / ins dalam pipa PowerShell biasa / dengan Pengalihan PowerShell tanpa ambiguitas.

      • Anda secara opsional dapat menggunakan string _expandable_ ( "...." atau varian string di sini) untuk menyematkan nilai variabel _PowerShell_ di baris perintah (sesuatu yang tidak dapat dilakukan --% ).


Karena kekuatan yang telah disimpulkan bahwa # 1995 tidak dapat diperbaiki agar kompatibilitas mundur tidak rusak - lagipula, semua solusi yang ada akan rusak, lihat https://github.com/PowerShell/PowerShell/issues/1995#issuecomment -562334606 - the Hal terbaik yang dapat kita lakukan adalah mendukung keikutsertaan ke dalam perilaku yang tepat dengan sintaksis yang sesingkat mungkin, sehingga meminimalkan rasa sakit karena harus keluar dari cara Anda untuk mendapatkan perilaku yang seharusnya selalu menjadi default.

Oleh karena itu: sintaks khusus seperti &! hanya boleh diberikan sebagai pilihan untuk meneruskan argumen yang tepat ke program eksternal untuk mengatasi # 1995 , berdasarkan perilaku yang diusulkan dalam RFC @TSlivede - lihat https://github.com/PowerShell/PowerShell-RFC/pull/90. Jika versi PowerShell yang akan datang pernah diizinkan untuk merusak kompatibilitas ke belakang, maka pemanggilan / pemanggilan langsung dengan & yang seharusnya menunjukkan perilaku ini.

Dari perspektif pengguna, ini berarti: Yang perlu saya lakukan adalah memenuhi persyaratan sintaks _PowerShell_ - lihat https://github.com/PowerShell/PowerShell/issues/1995#issuecomment -640711192 - dan saya dapat mengandalkan PowerShell untuk dengan kuat meneruskan token verbatim yang dihasilkan ke program target - _ini adalah mandat inti dari shell apa pun, yang sayangnya tidak pernah dipenuhi PowerShell sehubungan dengan program eksternal_.

Misalnya, perintah berikut - yang saat ini _not_ berfungsi sebagaimana mestinya (saat dipanggil secara langsung atau dengan & - lihat masalah dokumen ini ) - seharusnya berfungsi:

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`

Mereka yang mencari solusi dalam versi PowerShell saat ini / sebelumnya dapat menemukan fungsi sederhana yang akan mencakup sebagian besar kasus penggunaan di https://github.com/PowerShell/PowerShell/issues/1995#issuecomment -303345059 (batasan dibahas di https: // github.com/PowerShell/PowerShell/issues/1995#issuecomment-649560892), dan versi yang lebih rumit di https://github.com/PowerShell/PowerShell/issues/1995#issuecomment -562334606

PS: Masalah penemuan operator (tidak hanya berbasis simbol) adalah masalah terpisah yang perlu ditangani dengan benar: solusinya adalah _enhance Get-Help untuk memungkinkan pencarian operator_ - lihat # 11339, yang juga tautan ke solusi sementara.

Karena kekuatan yang telah disimpulkan bahwa # 1995 tidak dapat diperbaiki agar kompatibilitas mundur tidak rusak - lagipula, semua solusi yang ada akan rusak, lihat # 1995 (komentar) - hal terbaik yang dapat kita lakukan adalah mendukung keikutsertaan ke dalam perilaku yang tepat dengan sintaks yang sesingkat mungkin, sehingga meminimalkan rasa sakit karena harus keluar dari cara Anda untuk mendapatkan perilaku yang seharusnya selalu menjadi default.

@ mklement0 Saya pikir keikutsertaan adalah bagian dari https://github.com/PowerShell/PowerShell/issues/1995 dan itu ditolak. Jadi bagi saya itu terdengar seperti angan-angan. Apakah aku salah?

@AndrewSav , kami awalnya hanya membahas keikutsertaan melalui konfigurasi atau variabel preferensi.

Namun, @joeyaiello mengatakan hal berikut di https://github.com/PowerShell/PowerShell/issues/1995#issuecomment -653164987 ketika dia menutup masalah (penekanan ditambahkan):

Apa pun yang kita sentuh di sini terlalu banyak perubahan yang merusak, dan kita harus mengatasi masalah ini dengan operator baru

Operator baru _adalah jenis keikutsertaan, tetapi tidak bermasalah, saya harap (meskipun perlu disayangkan, tetapi itulah harga kompatibilitas ke belakang).

Sementara proposal ini konon juga menyelesaikan # 1995, itu tidak, karena bertujuan (terutama) untuk mengakomodasi sintaks _other_ shells. Mengingat bahwa kedua masalah tersebut layak untuk diselesaikan, secara independen, proposal saya adalah ini:

  • Mari kita perkenalkan operator baru, tetapi gunakan hanya untuk memperbaiki # 1995 (melalui https://github.com/PowerShell/PowerShell-RFC/pull/90), yaitu untuk memperbaiki PowerShell _own_ (non-other-shell-emulating) rusak penanganan argumen yang diteruskan ke program eksternal.

    • Kode baru kemudian harus selalu menggunakan &! (atau bentuk apa pun yang kita putuskan) daripada & saat memanggil program eksternal (Anda dapat menganggapnya sebagai mencela & untuk program eksternal) .
    • Saat memanggil perintah _PowerShell_, &! harus bertindak seperti yang dilakukan & sekarang (tidak pernah ada masalah), sehingga memungkinkan penggunaan &! secara konsisten.
  • Untuk mengatasi masalah reuse-command-lines-from-other-shells, mari kita implementasikan Invoke-NativeShell / ins cmdlet yang memanggil shell asli yang sesuai dengan platform ( cmd /c pada Windows , /bin/sh -c pada platform mirip Unix) dengan baris perintah diteruskan sebagai _single string_.

    • Dalam kasus yang paling sederhana, dengan tidak ada ' di baris perintah, string biasa dengan tanda kutip tunggal akan bekerja; misalnya:

      in 'ls | kucing -n '

    • Dengan hadiah ' , mereka bisa menjadi _doubled_; misalnya:

      di 'echo' 'hai' '| kucing -n '

    • atau, jika Anda tidak ingin menyentuh baris perintah sama sekali, string di sini dapat digunakan (seperti yang telah ditunjukkan oleh @TSlivede) - meskipun sintaks ini sedikit lebih rumit, ini akan selalu berfungsi:

      di dalam @ '
      echo 'hai' | kucing -n
      '@

    • Selain itu, dengan menggunakan string _expandable_ (interpolasi) ( "..." atau @"<newline>...<newline>"@ ), Anda memiliki opsi untuk memasukkan variabel _PowerShell_ ke dalam string yang diteruskan ke shell asli (sesuatu yang --% tidak mendukung):

      $ foo = 'hai'
      di dalam @ "
      echo '$ foo' | kucing -n
      "@

    • catatan:

      • Invoke-NativeShell cmdlet akan menjadi pembungkus yang cukup tipis sekitar cmd /c / /bin/sh -c panggilan, yang jelas dapat Anda lakukan sendiri secara langsung, tetapi memiliki keuntungan yang tidak Anda perlukan mengetahui nama tertentu yang dapat dieksekusi dan sintaks lewat baris perintah.
      • Sebagai efek samping yang berpotensi menguntungkan, Anda akan dapat menggunakan parameter umum seperti -OutVariable , dan dapat memikirkan apakah akan membiarkan parameter -Error* bekerja pada _stderr_ (meskipun, untuk simetri, Invoke-Command harus, yang akan menjadi perubahan besar).

        • Karena shell mirip POSIX mendukung argumen _multiple_ dengan -c - yang pertama menyusun kode untuk dieksekusi, dan yang berikutnya argumen untuk diteruskan ke kode itu, dimulai dengan $0 (!) - mis. bash -c 'echo $@' _ 1 2 3 - argumen tambahan opsional harus didukung juga.

        • Karena shell asli platform dipanggil, panggilan tersebut menurut definisi _not_ portable, karena perbedaan mendasar antara cmd dan sh .Inilah sebabnya mengapa sangat penting untuk memperbaiki pengoperan argumen _own_ PowerShell (# 1995), karena ia kemudian menyediakan metode lintas platform yang dapat diandalkan untuk menjalankan program eksternal.


Bagian terakhir dari teka-teki itu adalah _dokumentasi_.

https://github.com/MicrosoftDocs/PowerShell-Docs/issues/5152 adalah proposal lama untuk menulis topik bantuan konseptual tentang memanggil program eksternal (mis., about_Native_Calls ), yang seharusnya, di satu lokasi, mencakup _semua_ aspek yang relevan untuk memanggil program eksternal; selain dari apa yang sudah dibahas di sana (kesalahan sintaksis karena karakter meta tambahan, tidak adanya pipeline byte mentah, non-integrasi dengan penanganan kesalahan PowerShell, ...), masalah yang dihadapi juga harus didiskusikan:

  • Bagaimana argumen yang lewat dengan " (dan argumen _empty_) rusak di (mudah-mudahan segera) versi sebelumnya (saat ini dibahas dalam proposal terpisah, https://github.com/MicrosoftDocs/PowerShell-Docs / issues / 2361), dan cara mengatasinya (manual \ -escaping atau penggunaan salah satu fungsi pembantu dari # 1995, salah satunya cukup ringkas untuk langsung dimasukkan ke dalam topik).

  • Bagaimana hanya &! harus digunakan untuk memanggil executable asli (eksternal), untuk memastikan pengoperan argumen yang tepat.

  • Bagaimana Invoke-NativeShell / ins dapat digunakan untuk menjalankan baris perintah _ditulis untuk shell_ asli platform apa adanya.

Menariknya, pengguna saat ini bisa:

  1. doa langsung
  2. & operator
  3. Mulai-Proses

Sama sekali tidak jelas bahwa pengguna harus menggunakan.

Setelah memperbaiki perilaku yang rusak, pengguna akan memiliki fitur-fitur berikut:

  1. doa langsung
  2. & operator
  3. Mulai-Proses
  4. &! operator
  5. Mulai-ProsesV2

Bukankah terlalu berlebihan bagi shell untuk menjalankan ping 127.0.0.1 ?

Ya, itulah perhatian utama saya dengan menambahkan operator lain juga @iSazonov. Ini sudah membingungkan, dan ini tidak akan membantu. Dokumentasi hanyalah sebagian dari teka-teki. Meskipun kami memiliki dokumentasi yang layak, fakta bahwa terdapat _lima cara berbeda_ untuk melakukannya, yang masing-masing berperilaku sedikit berbeda, akan selalu menyebabkan kebingungan.

Jika kita sama sekali peduli dengan UX, kita harus memilih untuk meningkatkan kasus yang ada daripada menambahkan lebih banyak lagi.

Jika kita sama sekali peduli dengan UX, kita harus memilih untuk meningkatkan kasus yang ada daripada menambahkan lebih banyak lagi.

Yang tidak bisa Anda lakukan karena Anda harus kompatibel ke belakang. Saya merasa kita berputar-putar. https://github.com/PowerShell/PowerShell/issues/1995 adalah itu dan ditutup karena alasan itu.

@septianjoko_

Kurangnya panduan yang ada perlu diatasi meskipun kami tidak memperkenalkan operator baru:

Untuk meringkas secara singkat:

  • Jangan gunakan Start-Process untuk menjalankan program _console_ (terminal) (kecuali - yang hanya tersedia di Windows - Anda ingin menjalankannya _di jendela baru_).

  • Doa dan permintaan langsung melalui & are _equivalent_; (mengesampingkan blok skrip), & hanya diperlukan untuk alasan _syntactic_, setiap kali nama perintah atau path adalah _quoted_ dan / atau berisi _variable reference_.


Setelah memperbaiki perilaku yang rusak, pengguna akan memiliki fitur-fitur berikut:
doa langsung

  • & operator
  • Mulai-Proses
  • &! operator
  • Mulai-ProsesV2
  • Tidak, tidak akan ada Start-ProcessV2 , hanya parameter _new_, -IndividualArguments - lihat https://github.com/PowerShell/PowerShell/issues/5576#issuecomment -552124719

  • Ya, akan ada &! (atau simbol apa pun yang kami putuskan), tetapi secara efektif _menggantikan & dan pemanggilan langsung_ (setidaknya untuk _ program eksternal_, tetapi Anda akan dapat menggunakannya dengan _all_ command forms) - yang seharusnya mudah untuk dikomunikasikan.

Bukankah terlalu berlebihan bagi shell untuk menjalankan ping 127.0.0.1 ?

ping 127.0.0.1 akan terus berfungsi, tetapi jika Anda ingin bash -c 'echo "one two"' berfungsi, Anda harus menggunakan
&! bash -c 'echo "one two"'

Itu sangat disayangkan, tetapi - mengingat bahwa pemanggilan langsung / & behavior _tidak dapat diperbaiki_ - menurut saya solusi terbaik.

Untungnya, ini adalah aturan sederhana untuk diingat: _Jika Anda ingin argumen yang dapat diprediksi diteruskan ke program eksternal, gunakan &! _

Bentuk alternatif keikutsertaan - konfigurasi (melalui powershell.config.json ) atau variabel preferensi - jauh lebih bermasalah:

  • Cakupan dinamis variabel preferensi membuatnya terlalu mudah untuk secara tidak sengaja menerapkan keikutsertaan ke kode lama yang tidak dirancang untuknya - lihat https://github.com/PowerShell/PowerShell/issues/1995#issuecomment -650262164

  • Konfigurasi akan berlaku untuk sesi secara keseluruhan, membuat penyisihan menjadi tidak mungkin sama sekali.

  • Dalam kedua kasus, tindakan diperlukan yang _pisah_ dari panggilan tertentu, dan melihat panggilan tertentu tidak akan memberi tahu Anda bagaimana akan berperilaku - sebaliknya, &! tidak menyisakan keraguan tentang perilaku yang akan terjadi.

Bagi pengguna akhir, tampilannya sama mengerikannya seperti kita meluncurkan kalkulator dan menemukan 5 tombol untuk operasi penambahan. 😄

Jika kita ingin memperbaikinya sedemikian rupa sehingga kita siap menghadapi kerumitan seperti itu, maka mungkin ini cukup untuk menerima perubahan yang mengganggu (untuk pemanggilan langsung dan & ) untuk menyederhanakan perilaku dan merilis V8.0.

Jika keinginan kami tidak begitu kuat, adalah mungkin untuk meningkatkan diagnostik secara memadai ( prog.exe param1 param2 -Whatif dan hal yang sama untuk Start-Process -WhatIf) sehingga menampilkan apa yang ditampilkan program testargs dan rekomendasi tentang bagaimana untuk melakukan pelarian dengan benar.

Pengembang skrip dapat meluangkan waktu untuk menguji dan menggunakan debugger. Namun dalam sesi interaktif, setiap pengguna menginginkan kesederhanaan, singkat dan jelas, dan ini melebihi segalanya.

@septianjoko_

maka mungkin ini cukup untuk menerima perubahan yang dapat menyebabkan gangguan (untuk pemanggilan langsung dan &) untuk menyederhanakan perilaku dan merilis V8.0

Anda pasti memiliki suara _my_ - tetapi apakah kekuatan yang mendukung rencana ini ? [_update_ - lihat # 13129]
Jika kita benar-benar mengambil perubahan sebesar ini, kita akhirnya dapat menangani semua bagasi bersejarah - lihat # 6745

Jika kami ingin memperbaikinya

Ada dua alasan bagus untuk sangat menginginkannya:

  • Untuk mengakhiri rasa sakit selama bertahun-tahun karena pengalihan argumen yang rusak - sebagaimana dibuktikan oleh # 1995, banyak masalah terkait, dan pertanyaan Stack Overflow yang tak terhitung jumlahnya.

  • Karena - seperti yang telah disebutkan beberapa kali sebelumnya - memanggil program eksternal dengan argumen adalah mandat _core dari shell_ manapun.

Secara historis, pada hari-hari khusus Windows, kelangkaan CLI eksternal yang mampu membuat ketidakmampuan untuk memanggil mereka dengan benar menjadi kurang bermasalah, dan pengguna yang tinggal di taman berdinding PowerShell (hanya memanggil perintah asli PowerShell) tidak merasakan sakitnya. Tapi waktu pasti telah berubah:

Kita hidup di era kekayaan CLI lintas platform yang sangat penting untuk tugas pengembangan, CI, dan penerapan.
Jika PowerShell ingin dianggap serius sebagai shell, masalah ini harus diatasi.


Bahkan jika v8.0 kompatibilitas yang diperbolehkan-untuk-istirahat-mundur terjadi (semoga saja), rilisnya bisa sangat lama, dan kami _also_ membutuhkan solusi sementara.

Sebanyak peningkatan yang diusulkan untuk dokumentasi diperlukan, saya rasa mereka sendiri tidak cukup meringankan rasa sakit, karena kurangnya solusi runtime yang tersedia.

Saya mendapatkan bahwa operatornya jelek, tetapi solusi non-breaking _necessitates_ sintaks tambahan (lebih banyak untuk mengetik), apa pun bentuknya.

Alternatif untuk &! yang tidak terlalu jelek, lebih mudah untuk mengetik, dan tidak "mencemari" bahasanya adalah dengan mengirimkan _function_ built-in dengan nama yang ringkas, seperti fungsi iep ( I nvoke- E xternal P rogram) yang menutupi semua masalah, ditampilkan di sini .
(Perhatikan bahwa kami telah mengirimkan fungsi yang menggabungkan fungsionalitas lain (mis., pause ) atau menampung cmd.exe pengguna (mis., cd.. [sic]).)

Jadi, untuk mendapatkan bash -c 'echo "one two"' agar berfungsi dengan baik, Anda akan memanggil iep bash -c 'echo "one two"'
Atau, untuk menggunakan skenario yang mungkin lebih realistis:

# 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" }'

Sekali lagi, pada akhirnya kita berbicara tentang _kompromi_ dalam layanan untuk menjaga kompatibilitas ke belakang - ini pasti mengganggu pengguna akhir.


meningkatkan diagnostik (prog.exe param1 param2 -Whatif dan sama untuk Start-Proses -WhatIf) sehingga menampilkan program testargs apa yang ditampilkan dan rekomendasi tentang cara melakukan pelarian dengan benar.

Karena direct / & -based invocation bukanlah panggilan cmdlet dan semua argumen dianggap sebagai argumen pass-through, memperlakukan -WhatIf sebagai parameter umum sama dengan perubahan yang merusak (betapapun tidak mungkin itu sedang dalam praktik).

Jika Anda bersedia menerima perubahan seperti itu, kami mungkin juga (juga) mendukung sakelar -DoItRight (atau yang berbasis simbol, mirip dengan --% ) sebagai keikutsertaan untuk perilaku tetap - dan itu menurut saya lebih buruk daripada pendekatan iep -prefix / &! .

(Opsi diagnostik yang tidak melanggar, saya kira, akan meningkatkan Invoke-Command , yang saat ini tidak mendukung -WhatIf - namun, jika kami menyediakan keikutsertaan yang terdokumentasi dengan baik ke perilaku, saya rasa ini tidak layak dilakukan.)

Saya setuju dengan @iSazonov bahwa situasinya tidak ideal untuk memperkenalkan hal lain untuk melakukan sesuatu yang seharusnya berfungsi, tetapi seperti yang disebutkan oleh @ mklement0 menunggu rilis yang dapat diperbaiki dengan benar, ini bisa menjadi waktu yang sangat sangat lama, dan banyak dari kita sangat membutuhkan solusi secepatnya. Sejauh yang bisa saya lihat, solusi terbaik saat ini adalah hanya menggunakan
https://github.com/PowerShell/PowerShell/issues/1995#issuecomment -562334606 kan?

@ mklement0 Saya tidak yakin bagaimana program iep / invoke-external dapat bekerja, karena cmdlet tunduk pada parameter yang sama yang kita coba perbaiki. Ini adalah masalah parser, bukan? Jika kami mencoba menyembunyikan semuanya di dalam cmdlet / function, saya akan membayangkan itu akan menjadi sangat kompleks karena harus membatalkan maksud munging / rekonstruksi. Atau apakah saya melewatkan sesuatu?

@oising :

Agar jelas: fungsi iep ditautkan memperbaiki # 1995, bukan tentang proposal _this_ yang utama (yang menurut saya _not_ layak untuk dikerjakan, seperti yang diperdebatkan di atas ), meskipun perhatikan bahwa maksud yang dinyatakan dalam OP adalah untuk _juga_ memecahkan # 1995.

1995 adalah tentang dapat mengandalkan sintaks _PowerShell_ (bukan shell lain) untuk meneruskan argumen ke program eksternal _ dengan setia, seperti yang terlihat kata demi kata oleh PowerShell setelah penguraiannya sendiri_.

Penguraian PowerShell sendiri baik-baik saja, dan tidak ada masalah selama Anda meneruskan argumen ke perintah _PowerShell_.

Sebaliknya, menyampaikan argumen ke _external program_ akan rusak parah, dan itulah yang diperbaiki iep .

Ini rusak karena _re-quoting dan escaping_ yang salah dari argumen _ di belakang scene_, ketika baris perintah yang akhirnya digunakan dibuat.
https://github.com/PowerShell/PowerShell-RFC/pull/90 mengusulkan perbaikan yang tepat (tanpa kesepakatan tentang cara menangani kompatibilitas ke belakang, dan dengan beberapa pertanyaan kecil yang masih harus dijawab), yang pada intinya bergantung pada baru-baru ini memperkenalkan System.Diagnostics.ProcessStartInfo.ArgumentList untuk melakukan pengutipan ulang dan pelolosan yang benar bagi kami (kami hanya meneruskan kumpulan argumen yang dihasilkan dari penguraian PowerShell sendiri) - yang, kebetulan, hanya diperlukan _pada Windows_; di Unix, secara masuk akal, _tidak ada baris perintah_ (di luar shell) saat Anda meneruskan argumen saat proses mulai: Anda hanya meneruskan argumen secara verbatim, sebagai array.

Pendeknya:

  • Menyediakan iep sebagai fungsi built-in akan menjadi pilihan stopgap upacara rendah untuk menawarkan argumen yang tepat diteruskan ke program eksternal, sampai perbaikan yang tepat - dalam konteks perubahan yang melanggar - dapat diimplementasikan

  • Cmdlet Invoke-NativeShell ( ins ) adalah solusi yang tepat - bukan stopgap - untuk menyediakan cara untuk memanggil _a baris perintah shell's_ (shell asli) yang berbeda, menggunakan sintaks _its_ - lihat di atas .

Saat ini, ada kasus di mana memotong dan menempelkan perintah PERL gagal berjalan seperti yang diharapkan di Python. Sosok pergi. Ini pasti sangat merugikan bagi semua pemotong-dan-penggembala di luar sana. Saya pikir Python harus memiliki operator khusus untuk itu.

Saya tidak yakin Anda telah memahami saran saya; apa yang Anda katakan adalah _ tepatnya_ apa yang saya katakan. Izinkan saya lebih bertele-tele dengan beberapa petunjuk yang dikapitalisasi secara strategis: 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 $_ }

Apa yang kulewatkan di sini? Jika pipa muncul setelah --% itu hanya karakter bodoh lainnya: sebuah argumen. Tidak ada mengutak-atik prioritas operator. Jika terdapat dalam pipeline atau subekspresi bersarang, mulailah mengurai PowerShell lagi.

Pikiran?

Apa yang Anda lewatkan adalah kebutuhan untuk melewatkan tanda kurung tutup sebagai argumen ke program eksternal. Ini adalah pendekatan DWIM yang khas — tetapi PowerShell tidak HAL.

Terima kasih untuk semua masukan mendetail, semuanya. Berbicara seperti diriku di sini. Beberapa poin uber sebelum saya membahas lebih dalam:

  • Saya masih belum bergabung dengan vNext / 8.0 yang memutuskan untuk memecahkan serangkaian hal baru. Kompatibilitas ke belakang penting. Saya tahu ini menyakitkan, dan saya lebih suka hidup di dunia di mana kita bisa kembali dan memperbaiki setiap kesalahan yang pernah dibuat PowerShell, banyak yang tidak disengaja. Tetapi sebagian besar pengguna PS tidak nongkrong di sini dalam masalah, selutut dalam kasus tepi SO. Mereka telah menyalin / menempel solusi yang sama ke sesuatu selama 4-10 tahun, mereka tidak selalu tahu mengapa itu berhasil, dan mereka tidak peduli bahwa kami "memperbaiki kesalahan" ketika skrip mereka rusak saat peningkatan. Mereka hanya tahu bahwa "memperbarui PS telah merusak saya, dan saya tidak dapat mempercayai pembaruan", dan kemudian kami berakhir dengan semakin banyak pengguna yang memperlambat pembaruan dan adopsi mereka.
  • Saya pikir beberapa orang dalam masalah ini mungkin memproyeksikan banyak harapan dan keinginan yang berbeda ke dalam masalah ini, atau melihatnya sebagai salah satu / atau dengan perbaikan lainnya. Saya menyadari bahwa saya memperburuknya dengan menutup # 1995, dan saya minta maaf untuk itu (meskipun saya akan mengatakan, saya masih tidak yakin apakah ada yang benar-benar dapat diperbaiki, tetapi kita akan melihat lebih keras), tetapi ini benar-benar merupakan solusi "pintu jebakan" yang membebaskan pengguna baru dan berpengalaman dengan cepat tanpa membiarkan rasa frustrasi meningkat. Kami masih dapat melakukan percakapan jangka panjang tentang perbaikan pada sisi parsing PS rumah sehingga kami dapat menawarkan solusi lintas platform yang sesungguhnya untuk semuanya.

Sekarang, komentar saat saya membaca:

  • Saya khawatir tentang keinginan yang diusulkan untuk menyelaraskan dengan #! (dengan &! atau $! mengingat, dalam kasus default, pengguna kemungkinan besar tidak akan menentukan penerjemah . Jika saya ingin melakukan sesuatu seperti $! net <stuff> , net.exe bukan penerjemah saya. Dan di non-Windows, hal "asli" yang harus dilakukan masih meneruskan ke sh / bash / apa pun sebelumnya meneruskan ke biner yang dijalankan. Misalnya saya tidak ingin Python mem-parsing *.py dalam string $! /usr/bin/python *.py atau bahkan $! python *.py . Saya ingin Bash melakukan globbing dan kemudian menyerahkan daftar kecocokan dengan python .
  • Seperti yang disarankan @oising , saya lebih memilih --% sebagai operator, kelebihan beban untuk digunakan di depan. Kemudahan untuk ditemukan adalah masalah, dan mengingat bahwa kami sudah 10 tahun bekerja untuk membuat yang satu ini dapat ditemukan ( sekarang Google-dapat!, Saya katakan kami hanya melakukannya. (Saya adalah orang yang membuat @ SteveL-MSFT masukkan ke dalam proposalnya sebagai pertimbangan alternatif). Namun, pertanyaan: apakah kita memerlukan operator panggilan & sini? Mengapa tidak memulai baris dengan --% native.exe do /some $stuff ?
  • @rjmholt : Saya tidak sepenuhnya memahami komentar Anda di sini , tetapi menurut pendapat saya, kami mungkin tidak mengubah apa pun dengan perilaku --% ada setelah dieksekusi, tetapi menurut saya kami dapat melakukan "baru perilaku "dengan tempatnya sebelum dapat dieksekusi.
  • Baca ini dari @jazzdelightsme dan saya sangat setuju:

    Ini juga untuk sebagian besar pengguna ahli, yang hanya ingin menyalin / menempelkan perintah dari StackOverflow tanpa harus masuk dan mengutak-atik semuanya.

    Dalam pikiran saya, ini adalah aspek besar dari skenario, mungkin yang terbesar. Bukan hanya SO, juga, ini adalah dokumen dari seluruh web yang menganggap Anda berada dalam shell seperti Bash.

  • Terlepas dari apakah hal-hal seperti # 1995 diperbaiki, intinya adalah bahwa a) ada banyak kasus aneh seperti itu, dan b) sangat sulit untuk diperbaiki tanpa merusak orang. Ini belum tentu benar untuk mereka semua, tetapi kami telah cukup berhasil selama beberapa tahun terakhir sehingga jelas bagi saya bahwa kami memerlukan "pintu jebakan" seperti ini untuk mengeluarkan orang dari situasi sulit di mana mereka tidak ingin menyelam lubang kelinci dari kami bersarang melarikan diri (hanya untuk menemukan ada bug seperti # 1995 yang mencegah mereka dari bekerja bahkan setelah mereka tahu apa yang mereka tahu).

Dalam meninjau komentar, saya rasa ada dua pertanyaan terbuka yang masih perlu kami jawab:

  1. Apakah kita terus mengurai pemisah perintah dan semuanya setelahnya di PowerShell, atau apakah pemisah perintah juga diteruskan secara verbatim ke shell asli?
    Saya mengatakan bahwa kita harus meneruskan semuanya secara verbatim ke shell asli karena saat ini itu adalah sesuatu yang tidak dapat Anda lakukan, dan solusi @oising dari tanda kurung terkemuka mungkin menjadi solusi karena kita masih dapat mendukung pipa, rantai pipa, dll. Jika Anda ingin mencampur / mencocokkan asli dan parsing PS (meskipun saya ingin mendapatkan beberapa pendapat dari mereka yang lebih dekat dengan parser).
  2. Apa operatornya?
    Seperti yang telah disinggung di atas, saya suka --% karena sudah mendapat reputasi sebagai operator "lakukan saja dulu", dan kita harus mengatur ulang kemampuan untuk dapat ditemukan dengan sesuatu yang baru. Saya memahami argumen seperti @ mklement0 bahwa, jika kita melakukan ini, kita mengubah arti teknis dari --% (dan @ SteveL-MSFT telah membuat argumen ini untuk saya juga), tetapi saya rasa kebanyakan orang di alam liar memikirkan --% dalam istilah "ia melakukan apa yang biasa dilakukannya di cmd". Saya tidak berpikir itu berlebihan untuk menyusun asumsi ini ke dalam definisi operator sebagai "lakukan apa yang dilakukan shell asli di sini".

Secara ortogonal, pikirkan saja skenario lain yang mungkin ingin kami dukung atau tidak.

Pada Windows, cmd (efektif) menyertakan direktori saat ini dalam pencarian PATH . Namun, PowerShell mengharuskan pengguna melakukan pra-pendahuluan ./ untuk mengeksekusi EXE apa pun (atau apa pun di PATHEXT ) jika direktori saat ini bukan di PATH .

Jadi pertanyaan terbuka saya adalah: apakah kita ingin benar-benar menyerahkan seluruh string perintah ke cmd? Saya akan mengusulkan bahwa jika kita benar-benar ingin menerangi skenario salin / tempel dengan operator ini, jawabannya adalah ya, karena beberapa dokumen / tutorial pihak ketiga tidak selalu merinci cara meletakkan alat yang mereka harapkan untuk Anda gunakan ke dalam PATH . Mungkin tidak terlalu penting, tapi saya ingin menghitungnya di sini.

  • Saya masih belum bergabung dengan vNext / 8.0 yang memutuskan untuk memecahkan serangkaian hal baru.

Ya, saya tidak tahu bagaimana Anda memperbaiki masalah ini tanpa memecahkan masalah yang sangat sulit. Selain itu, saya tidak tahu tentang kalian semua tetapi bahkan saya tidak ingin harus menyulap semua perbedaan pengikat / pengurai yang rumit ini saat menulis untuk beberapa versi.

Biasanya jika saya menentang perubahan yang melanggar, itu untuk orang lain. Namun, ini sepertinya akan menjadi PITA untuk ditangani bahkan untuk orang yang hadir di ITT.

  • Seperti yang disarankan @oising , saya lebih memilih --% sebagai operator, kelebihan beban untuk digunakan di depan. (...) Mengapa tidak memulai baris dengan --% native.exe do /some $stuff ?

Saya sangat menyukai ini. Idealnya sedekat mungkin dengan memanggil CreateProcess / exec (ditambah penanganan nix env var dan pengalihan masuk / keluar atau lampiran konsol). Atau mungkin kembali sepenuhnya ke cmd.exe / bash .

Saya juga tidak terjebak menyimpan & di depan --% . Saya bisa membenarkan gagasan untuk memperlakukan mentah --% seperti arahan / operator di kepala saya setidaknya. Bagaimana dengan multiline? Izinkan --% dengan @" dan "@ untuk substitusi dan sub-ekspresi var, dan kutipan tunggal @' dan '@ untuk lulus literal? Tanpa string di sini, itu hanya satu baris?

Seperti yang disarankan @oising , saya mendukung -% sebagai operator

Bekerja untuk saya.

Pertanyaannya, apakah kita bahkan memerlukan operator & panggilan di sini?

Selama saya masih bisa melakukan --% & $computedPathToNativeExe foo;@workspace maka saya akan baik-baik saja. Kami memang harus dapat menggunakan operator panggilan dengan ini.

Saya mengatakan bahwa kita harus meneruskan semuanya secara verbatim ke shell asli karena saat ini itu adalah sesuatu yang tidak dapat Anda lakukan

Sepakat.

Saya tidak berpikir itu berlebihan untuk menyusun asumsi ini ke dalam definisi operator (-%) sebagai "lakukan apa yang dilakukan shell asli di sini".

Juga setuju!

Juga, mungkin ini adalah cara untuk masuk ke fitur untuk mendefinisikan env vars sebelum dapat dieksekusi yang ditentukan hanya untuk sesi yang dapat dieksekusi (# 3316):

--% JEKYLL_ENV=production jekyll build

Hanya pemikiran saja.

@rkeithhill , gagasan dengan call native operator adalah bahwa baris tersebut tidak diproses oleh PowerShell dan dikirim secara verbatim ke "shell default" OS. Jadi dalam kasus ini, contoh pertama Anda --% & $computerPathToNativeExe foo;@workspace tidak akan berfungsi. Anda harus menggunakan metode saat ini dan melarikan diri sebagaimana mestinya. Kasus kedua --% JEKYLL_ENV=productoin jekyll build seharusnya berfungsi.

baris tidak diproses oleh PowerShell dan dikirim kata demi kata ke "shell default" OS

Oke, sepertinya masuk akal. Namun --% JEKYLL_ENV=productoin jekyll build ini hanya akan berfungsi di Linux / macOS tetapi tidak di Windows - setidaknya tidak tanpa bantuan dari PowerShell, bukan?

@rkeithhill saat ini diusulkan yang tidak akan pernah berfungsi di Windows karena bergantung pada shell "default" OS. Untuk PowerShell yang mendeklarasikan env var untuk suatu proses, kami memiliki masalah berbeda yang dibuka untuk membahasnya.

@ PowerShell / powershell-committee membahas hari ini, saya telah memperbarui proposal asli untuk mencerminkan hasil diskusi itu. Kami akan melanjutkan dengan penerapan fitur eksperimental dan mendapatkan lebih banyak umpan balik dari pengguna dengan kode yang berfungsi. Kami masih terbuka di sigil untuk operator, tetapi menggunakan --% untuk saat ini.

di mana $foo adalah nama file literal dan $PWD adalah direktori saat ini dalam WSL. Perhatikan bahwa dalam contoh pertama, Anda harus tahu untuk melarikan diri && agar dijalankan dalam WSL dan bukan di dalam PowerShell.

Baik $foo dan $PWD adalah referensi variabel yang akan dievaluasi oleh sh .

Untuk menyalurkan keluaran dari eksekusi tersebut kembali ke PowerShell, pengguna diharuskan menyimpan hasil ke dalam variabel terlebih dahulu:

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

Perhatikan bahwa tidak seperti operator panggilan & , Anda tidak dapat menggunakan sintaks PowerShell apa pun, jadi:

--% $commandline

akan mencoba mengeksekusi $commandline secara harfiah (di bawah cmd ) atau setelah ekspansi shell (di bawah sh ). PowerShell tidak akan mencoba menyelesaikan variabel itu.

Masalah potong & tempel diselesaikan hanya dengan menempelkan setelah &n diketik.

hanya dengan menempelkan setelah --%

Contoh di atas untuk wsl akan terlihat seperti:

Yang mana?

Karena semua argumen setelah --% diteruskan ke shell "default", untuk mendukung pipelining ke PowerShell, Anda perlu menggunakan variabel:

Ini adalah pengulangan.

Jika kita akan menambahkan sesuatu yang berguna, saya mengusulkan Pivot.

Mengapa kita tidak bisa memiliki sesuatu seperti Literal herestring

@! ""! @

Jadi kita dapat memiliki cara nyata untuk melakukan ini daripada -% yang juga memiliki host masalahnya sendiri.

Setidaknya dengan cara itu kita bisa mengubur masalah dengan taktik desain yang "lebih baik".
Dan kemampuan untuk dapat ditemukan untuk kasus edge ini berada di About_String tempat hal itu harus diselesaikan.

Hanya pemikiran saja.

Saya gagal untuk melihat bagaimana @!"…"!@ lebih baik daripada Invoke-NativeShell @"…"@ . Apakah kita mencoba membuat PowerShell lebih mirip Brainfuck?

@ yuliarrrr

Saya gagal untuk melihat bagaimana @!"…"!@ lebih baik daripada Invoke-NativeShell @"…"@ . Apakah kita mencoba membuat PowerShell lebih mirip Brainfuck?

Saya percaya, bahwa @ romero126 dimaksudkan untuk menyarankan literal herestring oneline, sehingga orang bisa menulis

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

dari pada

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

Jika herestring oneline seperti itu akan dipertimbangkan, saya sarankan untuk menggunakan sintaks seperti @"""…"""@ dan @'''…'''@ , ini akan membuat IMO lebih mudah untuk diketik daripada @!"…"!@ .


@ romero126 Bisakah Anda menjelaskan apa yang Anda maksud?

@ yecril71pl terima kasih telah menangkap kesalahan tersebut, memperbarui pesan teratas dengan perbaikan.

Tidak ditentukan apakah --% akan dijalankan sebagai baris perintah atau sebagai file batch.

Saya percaya, bahwa @ romero126 dimaksudkan untuk menyarankan literal herestring oneline, sehingga orang bisa menulis

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

dari pada

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

Jika herestring oneline seperti itu akan dipertimbangkan, saya sarankan untuk menggunakan sintaks seperti @"""…"""@ dan @'''…'''@ , ini akan membuat IMO lebih mudah untuk diketik daripada @!"…"!@ .

@ romero126 Bisakah Anda menjelaskan apa yang Anda maksud?

Saya yakin jika kami menambahkan fleksibilitas pada Strings untuk menangani data "hampir mentah" yang tidak diurai, kami tidak akan mengalami masalah tentang munculan ini.
@TSlivede Saya setuju hampir Sepenuhnya dengan apa yang Anda katakan. Hanya dengan sedikit variasi. Ini harus dapat menangani KEDUA baris tunggal dan Multiline tanpa interpolasi apa pun di dalam tanda kutip. Apa pun Sintaks yang kami gunakan untuk mewujudkannya, saya terbuka. Saya lebih fokus pada konsep ..

Dengan contoh-contoh ini, ia menambahkan banyak Fleksibilitas di mana saya tidak perlu "Invoke-NativeShell" karena hanya akan mengembalikan string. Yang berarti kita bebas untuk memanipulasinya seperti halnya string. Sehingga ini berpotensi bisa menjadi Pokok dari apa yang tampak hebat.

Pivot seperti ini juga berarti kami tidak perlu berurusan dengan masalah di atas di mana kami memutar roda kami hampir seperti solusi saat kami dapat menangani kasus tepi, vs mengatasi masalah secara keseluruhan.

Contoh Cepat:

# 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

Itu tidak mengatasi masalah sampul @ mklement0 di bagian kedua komentar ini . Faktanya adalah, kita tidak bisa hanya memberikan satu string ke setiap perintah; dalam banyak kasus mereka harus berpisah.

Saya yakin jika kami menambahkan fleksibilitas pada Strings untuk menangani data "hampir mentah" yang tidak diurai, kami tidak akan mengalami masalah tentang munculan ini.

Untuk inilah ' dan @' .

Dengan contoh-contoh ini, ia menambahkan banyak Fleksibilitas di mana saya tidak perlu "Invoke-NativeShell" karena hanya akan mengembalikan string. Yang berarti kita bebas untuk memanipulasinya seperti halnya string. Sehingga ini berpotensi bisa menjadi Pokok dari apa yang tampak hebat.

Perintah asli mengembalikan urutan string. @!" memiliki potensi untuk menjadi Pokok dari apa yang tampak seperti tidak dapat dipahami.

Saya yakin jika kami menambahkan fleksibilitas pada Strings untuk menangani data "hampir mentah" yang tidak diurai, kami tidak akan mengalami masalah tentang munculan ini.

Untuk inilah ' dan @' .

Dengan contoh-contoh ini, ia menambahkan banyak Fleksibilitas di mana saya tidak perlu "Invoke-NativeShell" karena hanya akan mengembalikan string. Yang berarti kita bebas untuk memanipulasinya seperti halnya string. Sehingga ini berpotensi bisa menjadi Pokok dari apa yang tampak hebat.

Perintah asli mengembalikan urutan string. @!" memiliki potensi untuk menjadi Pokok dari apa yang tampak seperti tidak dapat dipahami.

saya rasa anda sedang bingung. Dengan poin yang saya buat.
Tanda kutip tunggal dan Tanda kutip ganda hanya memperluas $ variabel atau tidak. Itu tidak secara otomatis keluar dari karakter. Itu juga membatasi saya sehingga saya tidak bisa lagi menggunakan karakter yang menentukannya. Jadi sebaliknya Agar berfungsi dengan baik seperti sekarang. Saya masih harus menghindari karakter yang merupakan inti dari mengapa kami perlu menyertakan &! Perintah.

Jika Anda memiliki solusi yang lebih baik, saya mendengarkan. Saya yakin ini lebih banyak menyentuh kasus tepi daripada menambahkan &!

Tanda kutip tunggal dan Tanda kutip ganda hanya memperluas $ variabel atau tidak. Itu tidak secara otomatis keluar dari karakter. Itu juga membatasi saya sehingga saya tidak bisa lagi menggunakan karakter yang menentukannya. Jadi sebaliknya Agar berfungsi dengan baik seperti sekarang. Saya masih harus menghindari karakter yang merupakan inti dari mengapa kami perlu menyertakan &! Perintah.

Karakter mana yang harus Anda hindari dan mengapa?

@ romero126 Sekarang saya bingung apa yang Anda katakan. Apakah Anda sadar, bahwa PowerShell memiliki string di sini ?

Saya sebelumnya berpikir, bahwa Anda mungkin menganggap sintaks Powerhell di sini string menjengkelkan (Setidaknya saya terkadang kesal, bahwa harus ada baris baru di awal dan akhir ...), tapi sekarang saya tidak begitu yakin apa Anda berkata, bisakah Anda menjelaskan?

@TSlivede , menyetujui di sini-string secara sintaksis agak rumit.

Ada proposal yang ada, # 2337, yang mengusulkan perbaikan, dan meskipun difokuskan untuk memungkinkan pembatas penutup diberi indentasi, @lzybkr juga mengusulkan variasi seperti Rust-like _single-line _ (- juga) di https: // github. com / PowerShell / PowerShell / issues / 2337 # Issuecomment -391152107, yang memungkinkan kami melakukan hal berikut, misalnya:

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

Kebutuhan untuk melarikan diri dapat dihindari dengan menggabungkan _multiple_ ' dengan @ , sesuai kebutuhan (misalnya, @'' can use @' here ''@ .

Dengan kata lain: ini akan menjadi peningkatan umum pada string literal PowerShell, dapat digunakan di mana-mana, yang juga akan mendapatkan keuntungan Invoke-NativeShell .

Mengingat # 2337 terutama berfokus pada hal lain, saya telah membuat proposal terfokus di # 13204 , dan saya sarankan kita melanjutkan percakapan di sana.

Kebutuhan untuk melarikan diri akan dihindari

Saya telah melihat ini beberapa kali di utas ini.

Setiap indikator tokeniser untuk memulai mode baru akan memerlukan mekanisme pelolosan, karena Anda perlu membedakan indikator ke tokeniser bahwa Anda meninggalkan mode tersebut dari bentuk literal karakter tersebut.

Bentuk paling alami saat ini adalah string yang dikutip tunggal:

  • ' : memulai tokenisasi kutipan tunggal
  • ' : mengakhiri tokenisasi tanda kutip tunggal
  • '' : tulis satu kutipan literal dalam string kutipan tunggal

Saya pikir alasan kita berbicara tentang melarikan diri meskipun ini adalah:

  • Operator --% menentukan terlalu banyak cara untuk keluar dari modenya ( | , && , || , ; , baris baru) dan memperbolehkan string di dalamnya (menghapus karakter ' mereka)
  • Herestrings dan co menyelesaikan ke satu argumen string dan bukan array dari mereka

Ingin meneruskan argumen ke pemanggilan yang dapat dieksekusi berarti kita sebenarnya berbicara tentang sintaks array:

  • Cara memulai array (memulai mode kata demi kata)
  • Cara memisahkan array (meneruskan satu argumen ke executable baru)
  • Bagaimana mengakhiri array (mengakhiri mode kata demi kata)

(Ini adalah konsep asli di * nix, karena exec mengharapkan sebuah array. Di Windows, saya pikir kita dipaksa untuk mengambil sebuah array, menserialisasinya ke sintaks string tertentu dan meneruskannya melalui CommandLineToArgvW . Namun, .NET menyediakan abstraksi berbasis array untuk keduanya - jadi array masih tetap masuk akal)

Itu berarti kita membutuhkan dua pelarian:

  • Literal pemisah array
  • Array diakhiri literal

Misalnya, katakanlah:

  • --% sebelum perintah menjadi sintaks verbatim baru
  • Bagaimana kita mengakhiri sintaks? baris baru dan ; mungkin?
  • Bagaimana kita memisahkan argumen? mungkin?

Pertanyaannya kemudian adalah:

  • Bagaimana kita mengirimkan ; literal atau baris baru?
  • Bagaimana kita mengirimkan literal?

Baris perintah asli bukanlah larik. Ini bisa berupa string atau AST. Karena PowerShell tidak tahu apa-apa tentang AST di shell asli, hanya string yang tersisa.

Baris perintah asli bukanlah larik. Ini bisa berupa string atau AST

Anda belum memberikan alasan apa pun untuk pernyataan ini.

Di sinilah PowerShell membangun AST untuk sebuah perintah (dalam bentuk apa pun, karena ia tidak tahu hingga runtime ketika perintah tersebut menyelesaikan jenis perintah apa itu):

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

Perhatikan bahwa elemen perintah (termasuk parameter dan argumen) ditambahkan ke dalam array.

Anda dapat melihat ini beraksi di PowerShell seperti ini:

> { 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

Array itu dikompilasi menjadi ekspresi di sini:

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

Dan kemudian itu diteruskan ke pemanggilan pipa di sini (perhatikan Expression.NewArrayInit(typeof(CommandParameterInternal[]), pipelineExprs) adalah tempat argumen diteruskan):

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

Saat runtime, ketika ekspresi terkompilasi dijalankan, itu menjadi panggilan metode ini , yang meneruskan ke panggilan ini yang memutuskan prosesor perintah apa yang akan digunakan:

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

Akhirnya, ketika pipeline dipanggil, array argumen itu terikat ke perintah native menggunakan NativeCommandParameterBinder :

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

Itu mengambil array argumen, yang menyertakan metadata AST seperti jenis string apa yang digunakan untuk setiap argumen, dan membangun string baru untuk pemanggilan argumen di NativeCommandProcessor sini:

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

Hal ini dilakukan karena .NET API yang saat ini kami gunakan untuk pemanggilan proses adalah versi lama "semua argumen dalam satu string", bukan versi baru di .NET Core yang memungkinkan Anda meneruskan array dan memungkinkan .NET membangun kembali pemanggilan sesuai kebutuhan dengan cara khusus platform.

Tapi kami menggunakan API itu adalah detail implementasi. Misalnya, kita dapat memanggil fork / exec langsung di * nix, seperti yang kita lakukan di sini:

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

Perhatikan bahwa exec sini mengambil sebuah array - kami melakukannya karena ini adalah cara paling sederhana dan langsung untuk meneruskan argumen ke syscall, yang pada akhirnya merupakan tujuan dari sintaks argumen verbatim.

@rjholt :

_Functionally_, semua kebutuhan sudah dicakup oleh bentuk string-literal yang ada, _jika Anda meneruskan baris perintah asli sebagai string_ tunggal, yang sangat saya sarankan, melalui Invoke-NativeShell / ins cmdlet baru.

Titik awal di sini adalah sebagai _satu string_, bukan array: ini adalah baris perintah _entire_ - untuk diurai _oleh target shell_ - dan paling masuk akal untuk merefleksikan ini di PowerShell seperti itu - sebagai lawan untuk mencoba dengan canggung mengikat sepatu sintaks shell yang berbeda ke dalam PowerShell dengan sesuatu seperti --%

Yang harus dilakukan Invoke-NativeShell adalah meneruskan string tunggal yang berisi seluruh baris perintah native-shell ke native shell melalui CLI-nya:

  • di Unix , ini berarti: berikan string apa adanya, _as whole_, sebagai elemen kedua dari argumen _array_ diteruskan ke exec (dengan -c menjadi elemen array argumen pertama, dan /bin/sh yang dapat dieksekusi); diekspresikan dalam istilah .NET dengan contoh sederhana, di mana printf "'%s'" foo | cat -n adalah konten verbatim dari string tunggal yang berisi baris perintah untuk dilewati (perhatikan penggunaan .ArgumentList , bukan .Arguments ; penggandaan ' s hanya artefak dari contoh ini):

    • $psi = [Diagnostics.ProcessStartInfo]::new('/bin/sh'); $psi.ArgumentList.Add('-c'); $psi.ArgumentList.Add('printf "''%s''" foo | cat -n'); [Diagnostics.Process]::start($psi).WaitForExit()
  • pada Windows , ini berarti: untuk mengakomodasi cmd quirks, isi argumen lpCommandLine dari CreateProcess sebagai berikut (dengan lpApplicationName diasumsikan sebagai nilai variabel lingkungan ComSpec , yang menunjuk ke cmd.exe ): "/c " + cmdLine , di mana cmdLine adalah seluruh string baris perintah sebagaimana adanya; diekspresikan dalam istilah .NET dengan contoh sederhana, di mana echo a^&b & ver adalah konten kata demi kata dari string tunggal yang berisi baris perintah untuk dilewati:

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

      • @ yecril71pl , ini menyiratkan jawaban atas pertanyaan Anda apakah semantik command-prompt atau batch-file akan digunakan: ini adalah yang pertama, seperti yang juga digunakan oleh bahasa skrip lainnya, seperti Python dengan os.system() ; implikasi (mungkin tidak menguntungkan) adalah bahwa Anda tidak akan dapat melarikan diri % karakter, dan variabel loop for harus menggunakan satu % (misalnya, %i bukan %%i ); dan bahwa Anda harus memberi awalan perintah loop-body dengan @ untuk mencegahnya di-echo (misalnya, for %i in (*.txt) do <strong i="56">@echo</strong> %i ).

Proses ini akan menjadi _transparent ke pengguna akhir_, sehingga yang perlu mereka fokuskan adalah meneruskan baris perintah native-shell _verbatim_, hanya perlu memenuhi persyaratan sintaks string-literal _PowerShell_:

Dengan formulir ins @'<newline>...<newline>'@ , Anda sudah _can_ menggunakan baris perintah native-shell apa adanya: lihat di atas untuk mengetahui bagaimana berbagai bentuk string-literal yang ada dapat digunakan, yang - karena ketersediaan _interpolating_ di sini- bentuk string ( @"<newline>...<newline>"@ ) juga - termasuk kemampuan untuk menggunakan variabel _PowerShell_ dan ekspresi dalam baris perintah (ketidakmampuan untuk melakukannya adalah salah satu kekurangan utama --% ).

Apa yang diusulkan oleh komentar saya sebelumnya adalah _bentuk umum baru dari string mentah literal_, yang _pisah dari proposal_ ini (dan logika Invoke-NativeShell panggilan akan menjadi _lebih nyaman_.

Alih-alih apa yang sudah dapat Anda lakukan (dengan asumsi perintah Invoke-NativeShell / ins ):

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

dengan literal mentah baris tunggal baru yang diusulkan, Anda dapat menyederhanakan menjadi:

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

Jika spesifikasi sintaks string-literal mentah baru ini perlu diperdebatkan, izinkan kami melakukannya di # 13204, bukan di sini.

Jadi membaca ulang proposal untuk memahami maksud aslinya, saya melihat itu sebenarnya hanya meminta sintaks yang lebih baik untuk /bin/sh -c '<command>' + versi cmd, bersama dengan logika pelarian string khusus untuk setiap shell target. Saya telah mendasarkan konsepsi awal saya pada sintaks khusus dan perlu bekerja dengan parser dan prosesor perintah asli, dan pada properti .NET ProcessStartInfo.Arguments menjadi sangat sulit untuk digunakan dengan benar dalam hal pengiriman kutipan .

Tetapi pada kenyataannya string Arguments baru saja diteruskan secara verbatim . Jadi yang perlu kita lakukan adalah melewatkan string seperti itu secara langsung.

Dalam hal ini, saya pikir sintaks baru sama sekali tidak diperlukan (itu hanya akan memperumit logika tokenisasi dan saya curiga akan membingungkan orang) dan sebaliknya ini hanya perintah baru, ins seperti yang Anda katakan. .NET memiliki beberapa logika untuk ini di sini yang akan kami paksa untuk diterapkan ulang, tetapi tidak apa-apa karena kami harus sedikit lebih pintar.

Beberapa komentar di @rjmholt 's komentar https://github.com/PowerShell/PowerShell/issues/13068#issuecomment -660.231.641

Setiap indikator tokeniser untuk memulai mode baru akan memerlukan mekanisme pelolosan, karena Anda perlu membedakan indikator ke tokeniser bahwa Anda meninggalkan mode tersebut dari bentuk literal karakter tersebut.

Saya setuju dan saya tidak berpikir sintaks string sebaris di sini dapat sepenuhnya menghindari kebutuhan untuk melarikan diri.

Operator -% mendefinisikan terlalu banyak cara untuk keluar dari modenya (|, &&, ||,;, baris baru) dan mengizinkan string di dalamnya (menghapus karakter mereka)

Saat berbicara tentang --% , apakah Anda mengacu pada tombol --% ? Jika demikian, lebih baik untuk menjelaskannya dalam komentar Anda, karena sekarang --% diusulkan untuk menjadi operator panggilan.

Ingin meneruskan argumen ke pemanggilan yang dapat dieksekusi berarti kita sebenarnya berbicara tentang sintaks array:

Usulannya adalah memanggil shell asli (sh atau cmd) dan meneruskan semuanya secara harfiah setelah operator panggilan --% , seperti sh -c ... . Jadi, bukan PowerShell yang meneruskan argumen ke target yang dapat dieksekusi. Dalam hal ini, saya pikir kita tidak memerlukan _an array syntax_, bukan?

Bagaimana kita mengakhiri sintaks? baris baru dan; mungkin?
Bagaimana kita memisahkan argumen? 'ruang' mungkin?

Saya pikir parsing kata demi kata berakhir di baris baru. Untuk meneruskan baris baru sebagai bagian dari argumen, gunakan \n Saya kira, seperti yang Anda lakukan di bash secara langsung.

Baris perintah asli bukanlah larik. Ini bisa berupa string atau AST

Anda belum memberikan alasan apa pun untuk pernyataan ini.

Di sinilah PowerShell membangun AST untuk sebuah perintah (dalam bentuk apa pun, karena ia tidak tahu hingga runtime ketika perintah tersebut menyelesaikan jenis perintah apa itu):

Jika proposal ini diterapkan, itu akan memperkenalkan konstruksi khusus di mana PowerShell tidak akan membangun AST sama sekali.

Senang mendengarnya, @rjmholt.

NET memiliki beberapa logika untuk ini di sini yang kami akan dipaksa untuk menerapkan ulang

Saya tidak berpikir kita benar-benar perlu menerapkan ulang apa pun, seperti yang ditunjukkan oleh perintah dalam komentar saya sebelumnya: pada Windows, gunakan .Arguments untuk whole-command-line-string pass-through ke WinAPI; di Unix, gunakan .ArgumentList untuk membuat argumen _array_ yang digunakan langsung dengan exec .

Jika proposal ini diterapkan, itu akan memperkenalkan konstruksi khusus di mana PowerShell tidak akan membangun AST sama sekali.

Itu akan membangun tipe AST yang berbeda, yang dirancang untuk tujuan ini. Jika bukan bagian dari AST maka pada dasarnya sama dengan komentar, tidak ada yang terjadi.

_Functionally_, semua kebutuhan sudah dicakup oleh bentuk string-literal yang ada, _jika Anda meneruskan baris perintah asli sebagai string_ tunggal, yang sangat saya sarankan, melalui Invoke-NativeShell / ins cmdlet baru.

Saya pribadi menyukai ide Invoke-NativeShell cmdlet, dalam beberapa hal lebih baik daripada operator panggilan --% . Perhatian utama yang saya dengar tentang ide ini adalah lebih banyak mengetik daripada --% + Ctrl + v dan membedakan literal here-string dari interpolating here-string adalah beban lain bagi pengguna (_Saya secara pribadi berpikir ins jauh lebih mudah untuk mengetik daripada --% _).

Perhatian utama yang saya dengar tentang ide ini adalah lebih banyak mengetik daripada --% + Ctrl + v dan membedakan literal here-string dari interpolating here-string adalah beban lain bagi pengguna (_Saya secara pribadi berpikir ins jauh lebih mudah untuk mengetik daripada --% _).

Mungkin PSRL bisa membantu. Mirip dengan masalah tentang penangan kunci untuk mengelilingi jalur yang ditempelkan, PSRL dapat membaca CommandAst , melihatnya ins dan dengan benar keluar dari string yang ditempelkan.

Itu akan membangun tipe AST yang berbeda, yang dirancang untuk tujuan ini. Jika bukan bagian dari AST maka pada dasarnya sama dengan komentar, tidak ada yang terjadi.

Tentu tapi pohon itu akan sepele. Ini tidak akan mencerminkan arti dari perintah yang akan dijalankan.

Mulai proses cmd.exe redirect stdin / stdio dan kita benar-benar dapat menggunakan string untuk memanggil-NativeCommand sama dengan bash

Senang mendengarnya, @ daxian-dbw.
Suka idenya, @SeeminglyScience .

membedakan literal here-string dari interpolating here-string adalah beban lain bagi pengguna

Saya pikir itu adalah _plus_, karena - tidak seperti --% - penggunaan @"<newline>...<newline>"@ memungkinkan Anda untuk secara langsung memasukkan nilai variabel _PowerShell_ dan ekspresi ke dalam baris perintah asli.

Tentu saja, itu mengasumsikan bahwa pengguna mengetahui perbedaan antara string yang dikutip tunggal (kata demi kata) dan yang dikutip ganda (interpolasi) dan tentang selektif ` -escaping $ , tapi menurut saya ini penting opsi (lanjutan) untuk dimiliki.

Untuk membantu pengguna potong-dan-tempel, fitur PSReadLine yang diusulkan harus default ke @'<newline>...<newline>'@ (verbatim).


Pada akhirnya, kami tidak ingin mempromosikan pola pikir di mana pengguna tidak perlu mengetahui dan memahami persyaratan sintaks unik PowerShell - sebagai gantinya, kami ingin mempromosikan pemahaman tentang mereka, mengingat kekuatan tambahan yang mereka bawa_.

Tetapi untuk mendorong pengguna menggunakan sintaks _own_ PowerShell, yang menurut definisi _cross-platform_, itu harus bekerja dengan dapat diprediksi .
Untuk itu, # 1995 harus diperbaiki , idealnya secara langsung, memungkinkan perubahan yang melanggar, atau, jika itu bukan pilihan, melalui upacara minimal _opt-in_.

Untuk meringkas:

  • Sesuatu seperti --% (formulir operator baru yang diusulkan di sini), menurut definisi fitur _platform-spesifik_, sama sekali bukan pengganti untuk memperbaiki # 1995 .

  • Invoke-NativeShell ( ins ) menghindari semua batasan dari operator --% diusulkan dan menyediakan solusi "pintu jebakan" yang disebutkan @joeyaiello : cara cepat untuk menjalankan baris perintah tertulis untuk shell asli, tanpa harus menyesuaikannya dengan sintaks PowerShell.

  • --% harus tetap dalam bentuk _argument_ aslinya saja, dan harus tetap menjadi fitur _Windows-only_ (yang _effectively_, meskipun tidak _technically_) - dengan kata lain: tidak diperlukan perubahan.

    • Setelah # 1995 diperbaiki, satu-satunya tujuan --% adalah untuk mengakomodasi kasus _edge di Windows_: memungkinkan Anda untuk mengontrol kutipan eksplisit dari baris perintah yang diteruskan ke program jahat seperti msiexec yang membutuhkan bentuk kutipan intra-argumen yang sangat spesifik.

Salah satu fitur lain yang saya inginkan di PS v7.x adalah kemampuan untuk memiliki perintah asli keluar dengan kode kesalahan menghentikan skrip saya, seperti set -e seperti yang dibahas dalam RFC ini. Jika solusi untuk itu adalah sesuatu seperti Invoke-NativeCommand , apakah itu membingungkan dengan Invoke-NativeShell ?

Hanya mencoba memutar film sedikit maju karena saya ingin fitur panggilan asli, saya benar-benar ingin skrip build & test saya salah saat memanggil msbuild, cl, cmake, Conan, npm, dll dan perintah asli itu keluar dengan kode keluar bukan nol tanpa harus mengingat untuk memeriksa $ LASTEXITCODE setiap saat. Jika implementasinya hanya melalui variabel preferensi lain misalnya $PSNativeCommandInErrorActionPreference maka saya kira itu akan berdampak pada pemanggilan shell asli - itu menjadi "perintah" asli dan semua?

Perhatian utama yang saya dengar tentang ide ini adalah lebih banyak mengetik daripada --% + Ctrl + v dan membedakan literal here-string dari interpolating here-string adalah beban lain bagi pengguna (_Saya secara pribadi berpikir ins jauh lebih mudah untuk mengetik daripada --% _).

Mungkin PSRL bisa membantu. Mirip dengan masalah tentang penangan kunci untuk mengelilingi jalur yang ditempelkan, PSRL dapat membaca CommandAst , melihatnya ins dan dengan benar keluar dari string yang ditempelkan.

Tapi bagaimana dengan:

$c = gcm ins
& $c ...

PSRL akan kesulitan mengenali apa yang terjadi di sana. Itu harus stateful, selesaikan alias in ke invoke-nativeshell, lalu cari tahu bahwa Anda ingin memanggil commandinfo, lalu demunge args? Saya benar-benar tidak menyukai gagasan casing khusus perintah palsu.

membedakan literal here-string dari interpolating here-string adalah beban lain bagi pengguna

Saya pikir itu adalah _plus_, karena - tidak seperti --% - penggunaan @"<newline>...<newline>"@ memungkinkan Anda untuk secara langsung memasukkan nilai variabel _PowerShell_ dan ekspresi ke dalam baris perintah asli.

Saya tidak mengikuti Anda @ mklement0. Mengapa --% bisa diajarkan untuk melakukan ini? Saya sudah memberikan ini sebagai kasus penggunaan.

Saya benar-benar tidak menyukai gagasan casing khusus perintah palsu.

Tidak ada perintah palsu di sini, hanya cmdlet yang bonafid, Invoke-NativeShell , alias ins .

gcm ins ( Get-Command ins ) akan memberikan informasi tentang alias ins dalam bentuk instance [System.Management.Automation.AliasInfo] , yang nantinya dapat Anda berikan ke & untuk permintaan, seperti perintah atau alias lainnya.

Oleh karena itu, contoh Anda akan bekerja persis seperti yang diharapkan - hanya saja jika Anda menggunakan jalan memutar gcm ( Get-Command ), Anda harus mengeja sintaks string-literal yang sesuai _yourself_, tanpa _perancah perintah kenyamanan opsional_ yang disediakan oleh PSRL _could_, jika saran @SeeminglyScience diterapkan:

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

Atau, jika sintaks string-literal mentah baru yang diusulkan di # 13204 diterapkan:

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

Tentu saja, jika Anda terbiasa dengan sintaks string literal PowerShell, string bertanda kutip tunggal juga dapat digunakan: cukup gandakan ' disematkan di dalam string '...' :

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

Mengapa --% bisa diajarkan untuk melakukan ini?

  • --% tidak memiliki pembatas penutup, yang mencegahnya digunakan dalam pipeline Powershell, yang merupakan pembatasan yang tidak dapat diterima (perhatikan bahwa (...) enklosur adalah _not_ sebuah opsi, karena hal itu menyiratkan pengumpulan semua keluaran di muka baris dalam memori daripada pemrosesan _streaming_).

  • Di Unix, --% tidak dapat _both_ mendukung (tidak lolos) $ sebagai metacharacter _and_ PowerShell sebagai metakarakter shell POSIX.

Sekali lagi: ada _tidak ada pembenaran untuk dan tidak ada manfaat untuk memasukkan sintaks _different shell_ ke PowerShell - berikan baris perintah native-shell _sebagai string_, ke ins , dan semua masalah konseptual akan hilang.

Invoke-NativeShell menyiratkan bahwa PowerShell bukanlah shell asli. Apakah asumsi itu selalu benar dan akan selalu benar?

@oising kasus penggunaan adalah seseorang menyalin dan menempelkan perintah asli dari README atau sesuatu. Jika mereka melakukan sesuatu yang lebih rumit daripada mengetik ins SPACE CTRL + v maka mereka hanya akan membangun dan melepaskan string mereka sendiri seperti biasa.

@bayu_joo

Tetapi untuk mendorong pengguna menggunakan sintaks _own_ PowerShell, yang menurut definisi _cross-platform_, itu harus bekerja dengan dapat diprediksi .
Untuk itu, # 1995 harus diperbaiki , idealnya secara langsung, memungkinkan perubahan yang melanggar, atau, jika itu bukan pilihan, melalui upacara minimal _opt-in_.

Ini terpisah dari pembahasan tentang ins / --% kan? Jika Anda tidak setuju, dapatkah Anda menjelaskan mengapa masalah itu akan memengaruhi perintah / sintaks baru?

@SeeminglyScience , ya, ini terpisah, tetapi itu belum jelas di utas ini.
Satu-satunya alasan # 1995 muncul di sini adalah bahwa ini awalnya ditutup untuk masalah ini (meskipun untungnya dibuka kembali sejak itu), dan OP di sini masih menyatakan bahwa masalah ini akan memperbaikinya ("Ini juga harus menyelesaikan masalah ini:") .
Oleh karena itu, saya ingin menekankan bahwa ins / --% akan _not_ alamat # 1995, yang memerlukan perbaikannya sendiri, segera.
(Hanya jika penyampaian argumen PowerShell sendiri berfungsi dengan baik, kami dengan hati nurani yang baik merekomendasikan agar pengguna mempelajari sepenuhnya dan merangkul sintaks PowerShell sendiri - yang seharusnya kami lakukan.)

@ SP3269 , kita bisa menyeberangi jembatan itu saat kita sampai di sana 😁.

Tapi serius:

Jika Anda menganggap "asli" sebagai "yang ditulis khusus untuk platform host [keluarga]", nama tersebut akan tetap sesuai, bahkan jika PowerShell seharusnya menjadi shell sistem default pada platform tertentu (saya berharap, tapi saya rasa itu realistis, setidaknya tidak di masa mendatang).

Adapun alternatifnya:

  • Invoke-[System]DefaultShell akan menjadi nama yang paling akurat (meskipun jelas tidak lagi berlaku jika PowerShell pernah menjadi shell default sistem), tetapi "asli" tampaknya menjadi istilah yang lebih umum digunakan di dunia PowerShell.

  • Invoke-LegacyShell memiliki beberapa justifikasi di Windows, tapi saya rasa pengguna Unix tidak akan terlalu ramah dengan istilah itu.

Saya pikir saya mulai mengungkap kebingungan total yang saya alami mencoba melacak motif, ide, dan masalah semua orang di sini. Tampaknya kami ( @ mklement0 dan saya, setidaknya) melihat ini sebagai dua solusi berbeda untuk dua pandangan berbeda dari masalah konseptual yang sama. Apa yang saya sarankan adalah menggunakan --% sebagai petunjuk ke _parser_ untuk mengubah cara penguraian dalam hubungannya dengan panggilan & operator (tidak harus menggunakan --% standalone.) Di sisi lain, Michael tampaknya melihat ins sebagai cmdlet drop-in untuk menggantikan broker perintah dan parser argumen internal milik Powerhell sendiri, dan tidak ingin mengubah parser PowerHell, sebagai gantinya, menggunakan string / here -string untuk menangkap parameter yang dimaksudkan (yang saya katakan dapat digunakan dengan --% juga.)

-% tidak memiliki pembatas penutup, yang mencegahnya digunakan dalam jaringan pipa Powershell

Poin ini saya tidak mengerti sama sekali. Itu tidak lebih kekurangan pembatas penutup daripada ins / invoke-nativecommand. Jika Anda perlu membatasi atau memberi makan dari LHS, gunakan string di sini, jika tidak, ini dianggap sebagai pernyataan tunggal.

Terlepas dari cara apa pun yang dipilih, tampaknya akan ada kebutuhan untuk memilih shell asli untuk mengirimkan baris perintah. Saya sarankan kita menggunakan variabel lingkungan COMSPEC di Windows (default ke %systemroot%\system32\cmd.exe ) dan SHELL di Linux (default ke /bin/bash ) - jika SHELL tidak ' t ada, kita harus menargetkan /bin/sh (yang dalam banyak kasus merupakan symlink untuk bash.)

-% tidak memiliki pembatas penutup, yang mencegahnya digunakan dalam jaringan pipa Powershell

Poin ini saya tidak mengerti sama sekali. Itu tidak lebih kekurangan pembatas penutup daripada ins / invoke-nativecommand. Jika Anda perlu membatasi atau memberi makan dari LHS, gunakan string di sini, jika tidak, ini dianggap sebagai pernyataan tunggal.

Pada dasarnya Anda tidak dapat memanggil hal-hal seperti cmd --% /c someapp | someOtherApp dan meminta cmd menangani pipeline; PowerShell masih menafsirkan pipeline (dan beberapa hal lain seperti && dan || yang seharusnya berguna untuk orang-orang Unix) sebagai token PowerShell alih-alih meneruskannya ke perintah asli sebagai bagian dari string argumen.

dan SHELL di Linux (default ke /bin/bash )

Tidak: shell _system_ pada platform mirip Unix adalah _invariably_ /bin/sh .
Ini berbeda dari shell interaktif _user_ yang diberikan (tercermin dalam $env:SHELL - tetapi, sayangnya, saat ini tidak jika _PowerShell_ adalah shell pengguna, lihat # 12150), yang (a) dapat dikonfigurasi dan (b) sering _defaults to_ /bin/bash , tetapi bahkan itu tidak diberikan, sebagaimana dibuktikan oleh macOS baru-baru ini beralih ke /bin/zsh sebagai shell interaktif default untuk pengguna baru.

Saya sarankan kita menggunakan variabel lingkungan COMSPEC di Windows

Poin bagus, itulah cara yang lebih baik untuk merujuk ke shell sistem (juru bahasa perintah) di Windows - Saya telah memperbarui perintah contoh di atas sesuai.

Salah satu fitur lain yang saya inginkan di PS v7.x adalah kemampuan untuk memiliki perintah asli keluar dengan kode kesalahan menghentikan skrip saya, seperti set -e seperti yang dibahas dalam RFC ini. Jika solusi untuk itu adalah sesuatu seperti Invoke-NativeCommand , apakah itu membingungkan dengan Invoke-NativeShell ?

Hanya mencoba memutar film sedikit maju karena saya ingin fitur panggilan asli, saya benar-benar ingin skrip build & test saya salah saat memanggil msbuild, cl, cmake, Conan, npm, dll dan perintah asli itu keluar dengan kode keluar bukan nol tanpa harus mengingat untuk memeriksa $ LASTEXITCODE setiap saat. Jika implementasinya hanya melalui variabel preferensi lain misalnya $PSNativeCommandInErrorActionPreference maka saya kira itu akan berdampak pada pemanggilan shell asli - itu menjadi "perintah" asli dan semua?

Kami memiliki Start-NativeExecution dalam modul build untuk tujuan itu.

Saya telah melihat itu. Bagaimana tepatnya Anda akan menggabungkan Start-NativeExecution dengan Invoke-NativeShell jika Anda ingin agar nanti secara efektif menggunakan kode keluar bukan nol? Saya benar-benar berharap sesuatu seperti PR # 3523 berhasil dengan fitur panggilan asli ini karena saya ingin keduanya bekerja sama. Saya kira jika panggilan asli berakhir diimplementasikan sebagai cmdlet (Invoke-NativeShell vs -%) maka -ErrorAction Stop dapat diimplementasikan untuk membuatnya melempar (mengakhiri kesalahan) pada kode keluar bukan nol.

-% tidak memiliki pembatas penutup, yang mencegahnya digunakan dalam jaringan pipa Powershell

Poin ini saya tidak mengerti sama sekali. Itu tidak lebih kekurangan pembatas penutup daripada ins / invoke-nativecommand. Jika Anda perlu membatasi atau memberi makan dari LHS, gunakan string di sini, jika tidak, ini dianggap sebagai pernyataan tunggal.

Pada dasarnya Anda tidak dapat memanggil hal-hal seperti cmd --% /c someapp | someOtherApp dan meminta cmd menangani pipeline; PowerShell masih menafsirkan pipeline (dan beberapa hal lain seperti && dan || yang seharusnya berguna untuk orang-orang Unix) sebagai token PowerShell alih-alih meneruskannya ke perintah asli sebagai bagian dari string argumen.

Ya, saya mengerti perilaku saat @ vexx32. Tapi kami tidak (setidaknya saya tidak) berbicara tentang perilaku saat ini --% - kita berbicara tentang meningkatkan itu, tidak ada? Mengapa saya merasa bahwa kita semua saling berbicara di sini? :)

Seperti yang saya katakan, jauh di atas, kita bisa meningkatkan & untuk bekerja dengan --% jadi ini mungkin . Saya juga berpikir kita perlu memperjelas tentang exec asli implisit versus pemanggilan eksplisit shell dengan argumen. Ini adalah sumber kebingungan yang konstan - bahkan untuk pengguna windows berpengalaman - bahwa cmd.exe (shell) diperlukan untuk "menjalankan" file executable lain; hal yang sama berlaku untuk linux / osx.

Ya, saya memahami perilaku _current_ @ vexx32 . Tapi kita tidak (setidaknya saya tidak) berbicara tentang perilaku _current_ dari --% - kita sedang berbicara tentang meningkatkannya, bukan? Mengapa saya merasa bahwa kita semua saling berbicara di sini? :)

Jadi nada saat ini untuk menyesuaikan --% adalah jika itu adalah tempat nama perintah biasanya, semua yang ada di sebelah kanannya diuraikan apa adanya (hingga baris baru) dan dikirim langsung ke bash / cmd. Tidak ada ruang sintaks PowerShell seperti di sini-string dan apa yang bukan karena itu memiliki semua masalah yang sama dengan --% dan prosesor perintah asli saat ini.

Saya telah melihat itu. Bagaimana tepatnya Anda akan menggabungkan Start-NativeExecution dengan Invoke-NativeShell jika Anda ingin agar nanti secara efektif menggunakan kode keluar bukan nol? Saya benar-benar berharap sesuatu seperti PR # 3523 berhasil dengan fitur panggilan asli ini karena saya ingin keduanya bekerja sama. Saya kira jika panggilan asli berakhir diimplementasikan sebagai cmdlet (Invoke-NativeShell vs -%) maka -ErrorAction Stop dapat diimplementasikan untuk membuatnya melempar (mengakhiri kesalahan) pada kode keluar bukan nol.

Saat ini akan menjadi Start-NativeExecution { Invoke-NativeShell <strong i="10">@whatever</strong> } .

Poin ini saya tidak mengerti sama sekali. Itu tidak lebih kekurangan pembatas penutup daripada ins / invoke-nativecommand. Jika Anda perlu membatasi atau memberi makan dari LHS, gunakan string di sini, jika tidak, ini dianggap sebagai pernyataan tunggal.

Invoke-NativeShell tidak _need_ pembatas penutup apapun karena ini adalah perintah biasa, sedangkan horor --% tidak.

dan SHELL di Linux (default ke /bin/bash )

Tidak: shell _system_ pada platform mirip Unix adalah _invariably_ /bin/sh .

Saya pikir hal itu harus setara dengan membuat file skrip yang dapat dieksekusi dan menjalankannya, yang mendelegasikan tugas memilih shell yang tepat ke sistem operasi dan kita tidak boleh diganggu. Termasuk, jika dimulai dengan #! , biarlah.

Ide di balik Invoke-NativeShell adalah menyediakan pembungkus kenyamanan di sekitar _CLI_ shell asli.

  • Di Unix, itu sudah cukup, dan membuat file skrip tambahan tidak hanya memperkenalkan overhead tambahan, tetapi kemudian melaporkan nilai acak di $0 (jalur file skrip), sedangkan pemanggilan melalui CLI dapat diprediksi berisi /bin/sh dan bahkan dapat diset secara eksplisit dengan mengikuti kode-argumen dengan argumen lain (misalnya, sh -c 'echo $0' foo )

    • (Sebagai tambahan: membuat skrip shell dengan baris shebang #!/bin/sh berarti menargetkan shell sistem dengan path lengkap sama eksplisitnya dengan memanggil /bin/sh secara langsung).
  • Di Windows, eksekusi melalui file batch _would_ membawa keuntungan (tetapi tidak untuk mendelegasikan tugas untuk menemukan shell sistem, yang dapat diprediksi $env:ComSpec ), karena ini akan menghindari masalah dengan % escaping dan for perilaku yang disebutkan di atas .

Untuk menangani yang terakhir sebagai rasa hormat (sehingga pengguna tidak perlu menulis file batch tambahan mereka sendiri), untuk kejelasan konseptual, kami dapat menawarkan
-AsBatchFile beralih sebagai _opt-in_.

Yang mengatakan, jika ada konsensus bahwa mayoritas baris perintah publik cmd digunakan untuk cut-and-paste ditulis dengan semantik _batch-file_ ( %%i daripada %i sebagai variabel loop, kemampuan untuk melarikan diri dari kata demi kata % sebagai %% ), mungkin selalu menggunakan aux. file batch _ pada Windows_ (sementara tetap menggunakan CLI di Unix) adalah solusi yang lebih baik - Saya tidak terlalu yakin tentang hal ini, tetapi harus didokumentasikan dengan jelas, terutama karena itu berarti menunjukkan perilaku yang berbeda dari bahasa skrip lainnya.

@bayu_joo

Bagi saya, integrasi-of-native-error RFC yang Anda tautkan layak untuk ditangani sama mendesaknya dengan # 1995:

Keduanya mewakili langkah-langkah yang diperlukan untuk membuat program eksternal (utilitas asli) warga kelas satu di PowerShell (sebanyak mungkin secara konseptual), _yang seharusnya selalu ada_.

Menjadi warga negara kelas satu berarti: pemanggilan _direct_ (dengan & hanya diperlukan untuk alasan _syntactic_, secara situasional), bukan _ melalui cmdlet_.
Dengan kata lain: tidak boleh ada Invoke-NativeCommand cmdlet atau Start-NativeExecution cmdlet.

(Sebagai tambahan: Start-NativeExecution salah nama, karena banyak fungsi dalam modul build adalah; Start signal _asynchronous_ operation, sedangkan kebanyakan dari fungsi ini adalah _synchronous_ - lihat pembahasan tentang Start-Sleep di https://github.com/MicrosoftDocs/PowerShell-Docs/issues/4474).

Oleh karena itu, Invoke-NativeShell tidak memerlukan pertimbangan khusus: PowerShell, seperti yang sudah dilakukannya, akan menetapkan $LASTEXITCODE berdasarkan kode keluar yang dilaporkan oleh proses eksekusi native-shell ( cmd / sh ) dipanggil.

Kemudian mekanisme yang diusulkan di RFC akan bertindak di atasnya, karena akan bertindak pada executable yang dipanggil secara langsung (misalnya, jika $PSNativeCommandErrorAction = 'Stop' disetel, kesalahan penghentian skrip akan terjadi jika $LASTEXITCODE bukan nol. )

(Penyisihan singkat - diskusi ini tidak termasuk di sini: Adapun mekanisme _per-call_: sesuatu seperti
/bin/ls nosuch || $(throw 'ls failed) berfungsi, seperti halnya /bin/ls nosuch || $(exit $LASTEXITCODE) (setara dengan shell POSIX /bin/ls nosuch || exit ); # 10967 membahas mengapa sayangnya kita tidak dapat menghindari $(...) (tanpa perubahan besar pada tata bahasa); Demikian pula, perlu merujuk ke $LASTEXITCODE secara eksplisit mungkin tidak dapat dihindari.)

(Sebagai tambahan: membuat skrip shell dengan baris shebang #!/bin/sh berarti menargetkan shell sistem dengan path lengkap sama eksplisitnya dengan memanggil /bin/sh secara langsung).

Bukan itu yang ingin saya katakan. Saya ingin mengatakan bahwa PowerShell tidak perlu tahu apa shell defaultnya karena sistem operasi memiliki fitur ini di dalamnya. Linux tahu cara menjalankan skrip yang dapat dieksekusi jika tidak dimulai dengan #! atau dimulai dengan sesuatu yang lain, seperti #!/usr/bin/env python dan Windows tahu apa yang harus dilakukan untuk memanggil skrip .CMD , jadi kita sebaiknya tidak mengintip ke dalam %COMSPEC% 'n'stuff baik IMHO. Windows juga dapat menjalankan skrip lain tetapi ini didasarkan pada ekstensi file skrip, jadi jelas tidak berlaku untuk kasus ini.

Sekali lagi, mandat Invoke-NativeShell harus memanggil _CLI_ dari shell native, tidak membuat file skrip tambahan (dengan efek samping) di belakang layar (kecuali untuk alasan yang berbeda, seperti dibahas di atas ).

Sehubungan dengan penentuan shell sistem dengan tepat, tidak ada masalah yang harus diselesaikan di sini: pengkodean keras /bin/sh pada Unix sangat tepat, seperti halnya berkonsultasi dengan $env:ComSpec pada Windows.

Tidak, platform Unix di tingkat pemanggilan sistem tidak _not_ tahu cara mengeksekusi file teks biasa yang dapat dieksekusi _tanpa baris shebang_; bahwa Anda masih _bisa_ memanggil file tersebut adalah fitur kenyamanan dari kerangka seperti POSIX: mereka mencoba exec , kemudian _fall back_ untuk menafsirkan file seperti yang ditulis _untuk mereka_; yaitu, itu adalah shell seperti POSIX apa pun yang sedang dijalankan yang akhirnya mengeksekusi file - sedangkan PowerShell hanya _fails_, karena tidak menerapkan penggantian kesopanan ini (Anda akan mendapatkan Program 'foo' failed to run: Exec format error ).

Oleh karena itu, tidak disarankan untuk membuat skrip seperti itu.

Tidak, platform Unix di tingkat pemanggilan sistem tidak _not_ tahu cara mengeksekusi file teks biasa yang dapat dieksekusi _tanpa baris shebang_; bahwa Anda masih _bisa_ memanggil file tersebut adalah fitur kenyamanan dari kerangka seperti POSIX: mereka mencoba exec , lalu _fall back_ untuk menafsirkan file seperti yang ditulis _untuk mereka_; yaitu, itu adalah shell seperti POSIX apa pun yang sedang dijalankan yang akhirnya mengeksekusi file - sedangkan PowerShell hanya _fails_, karena tidak menerapkan penggantian kesopanan ini (Anda akan mendapatkan Program 'foo' failed to run: Exec format error ).

csh tidak seperti POSIX dan tidak gagal pada exec skrip kosong. Ini memanggil sh . Begitu juga perl .

Saya harap jelas bahwa ini membuat maksud saya: _ terserah setiap shell_ untuk memutuskan apa yang harus dilakukan, dan bahasa shell / scripting yang berbeda melakukan hal yang berbeda; PowerShell saat ini baru saja gagal - jika harus membuat pilihan, dan Anda ingin pilihan itu menjadi /bin/sh , kita kembali ke titik awal: /bin/sh harus diasumsikan.

Saya harap jelas bahwa ini membuat maksud saya: _ terserah setiap shell_ untuk memutuskan apa yang harus dilakukan, dan bahasa shell / scripting yang berbeda melakukan hal yang berbeda; PowerShell saat ini baru saja gagal - jika harus membuat pilihan, dan Anda ingin pilihan itu menjadi /bin/sh , kita kembali ke titik awal: /bin/sh harus diasumsikan.

exec dalam perl adalah panggilan sistem langsung, perl tidak memodifikasinya dengan cara apa pun. Secara khusus, ini tidak _memilih_ penerjemah.

Tentu saja, itu mengasumsikan bahwa pengguna mengetahui perbedaan antara string yang dikutip tunggal (kata demi kata) dan yang dikutip ganda (interpolasi) dan tentang selektif ` -escaping $ , tapi menurut saya ini penting opsi (lanjutan) untuk dimiliki.

Mungkin hanya saya, tapi saya akan menukar seribu " untuk satu -f .

@ yuliarrrr

exec di perl adalah panggilan sistem langsung, perl tidak memodifikasinya dengan cara apa pun. Secara khusus, tidak memilih penerjemah.

Itu tidak benar jika ia bekerja dengan skrip tanpa baris #! . Syscall exec di linux tidak berfungsi tanpa #! , karena seseorang dapat dengan mudah menguji:

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$ 

Edit: Saya baru saja memperhatikan, bahwa jika Anda menggunakan fungsi perpustakaan execlp maka sesuai dengan halaman manual:

Jika header file tidak dikenali (percobaan execve (2) gagal dengan kesalahan ENOEXEC), fungsi ini akan mengeksekusi shell (/ bin / sh) dengan jalur file sebagai argumen pertamanya. (Jika upaya ini gagal, pencarian lebih lanjut tidak dilakukan.)

Namun ini bukan fitur "linux" tetapi dari pustaka gnu c - dan menurut halaman manual, fitur ini secara eksplisit menggunakan / bin / sh dan bukan shell yang dapat didefinisikan pengguna. (Hardcode di sumber posix/execvpe.c ( new_argv[0] = (char *) _PATH_BSHELL; ) dan sysdeps / unix / sysv / linux / paths.h (atau sysdeps / generic / paths.h - Saya tidak tahu header mana yang digunakan ...) ( #define _PATH_BSHELL "/bin/sh" ))

Namun ini bukan fitur "linux" tetapi dari pustaka gnu c - dan menurut halaman manual, fitur ini secara eksplisit menggunakan / bin / sh dan bukan shell yang dapat didefinisikan pengguna. (Hardcode di sumber posix/execvpe.c ( new_argv[0] = (char *) _PATH_BSHELL; ) dan sysdeps / unix / sysv / linux / paths.h (atau sysdeps / generic / paths.h - Saya tidak tahu header mana yang digunakan ...) ( #define _PATH_BSHELL "/bin/sh" ))

Karena berasal dari sysdeps/**/linux , ini adalah hal Linux. Ini mungkin juga merupakan hal yang umum tetapi dapat diganti - jelas tidak secara lokal tetapi per OS.

Ya, saya memahami perilaku _current_ @ vexx32 . Tapi kita tidak (setidaknya saya tidak) berbicara tentang perilaku _current_ dari --% - kita sedang berbicara tentang meningkatkannya, bukan? Mengapa saya merasa bahwa kita semua saling berbicara di sini? :)

Jadi nada saat ini untuk menyesuaikan --% adalah jika itu adalah tempat nama perintah biasanya, semua yang ada di sebelah kanannya diuraikan _as is_ (hingga baris baru) dan dikirim langsung ke bash / cmd. Tidak ada ruang sintaks PowerShell seperti di sini-string dan apa yang bukan karena itu memiliki semua masalah yang sama dengan --% dan prosesor perintah asli saat ini.

Ya Tuhan ... Apakah semua orang hanya mencoba menjebakku? 😄 Tidak, Patrick - jika Anda ingin menggunakan ekspresi PowerShell, gunakan string di sini dengan --% . Jika Anda ingin multiline, gunakan di sini-string. Jika Anda ingin multline tanpa substitusi variabel, Anda dapat menggunakan kutipan tunggal di sini-string.

Bagaimanapun, saya tidak memiliki skin dalam game ini dan saya pikir saya sudah cukup bicara. Saya masih berpikir ada sesuatu yang sangat salah tentang penggunaan cmdlet untuk mengikuti shell lain dari dalam shell. Itu hanya kikuk. Ini sangat kikuk ketika Anda menggunakan cmdlet untuk mengeksekusi shell lain untuk menjalankan perintah asli yang tidak memerlukan shell sekunder itu sejak awal. Semuanya berbau tidak enak.

edit: kata terakhir

Judul item ini adalah "panggil operator asli." Saya melihat peluang yang terbuang percuma ketika kita sudah memiliki operator panggilan & dan kita sudah memiliki token yang dirancang untuk menangani argumen yang lewat ke perintah asli, --% . Saat ini, menggunakan & dengan --% TIDAK dikenali dan dengan demikian TIDAK akan memperkenalkan perubahan yang dapat merusak jika kita memutuskan untuk mengaktifkan skenario ini dan memberikan perilaku khusus untuk memperbaiki masalah yang dibahas di sini.

jika Anda ingin menggunakan ekspresi PowerShell, gunakan string di sini dengan --% . Jika Anda ingin multiline, gunakan di sini-string.

Inti dari operator ini adalah tidak mengurai sintaks PowerShell secara harfiah . Tidak ada yang namanya di sini-string. Tidak ada yang namanya konstanta string yang dikutip. Ini "kirim teks ke kanan apa adanya" bukan "evaluasi ekspresi ke kanan, ubah menjadi string, dan kirim nilainya"

Jadi misalnya, jika Anda memiliki ini:

--% @'
echo my native command
'@

itu akan diterjemahkan ke:

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

Kecuali Anda akan mendapatkan kesalahan parser karena '@ hanya akan menjadi awal dari konstanta string kutip tunggal yang berisi @ .

Saya pikir mungkin Anda membayangkan implementasinya secara berbeda sehingga kurang lebih sama dengan pitch untuk ins , tetapi di atas adalah pitch saat ini sedang dibahas untuk --% .

Juga perlu dicatat bahwa ini adalah cara kerja fungsionalitas yang ada. Contoh ini bekerja dengan cara yang hampir sama:

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

Saya ulangi:

Saat ini, menggunakan & dengan -% TIDAK dikenali / tidak ditentukan dan dengan demikian TIDAK akan memperkenalkan perubahan yang dapat menyebabkan gangguan jika kita memutuskan untuk mengaktifkan skenario ini dan

Biarkan saya mengejanya lebih jelas: Izinkan string di sini mengikuti --% bila digunakan dengan &

Hah itu masalah besar - ya saya melewatkannya, maaf @oising.

Tentang ide itu saya pikir akan sedikit membingungkan untuk memiliki --% mean stop parsing dalam beberapa konteks dan "melakukan pekerjaan yang lebih baik pada pengikatan argumen asli" pada orang lain (juga dengan membuatnya bekerja seperti Invoke-NativeShell jika itu yang Anda maksud).

Terima kasih telah menggali lebih dalam tentang exec , @TSlivede. Izinkan saya mencoba meringkas dan karena itu mudah-mudahan menutup garis singgung ini; berlaku untuk Linux dan macOS:

Tidak ada fungsi sistem (atau pustaka) yang disebut exec di Unix, hanya ada _family_ fungsi terkait dengan exec dalam namanya (kebanyakan sebagai awalan).

  • Fungsi _system_ ( man bagian 2 ), execve pada intinya, _fail_ saat Anda mencoba menjalankan skrip tanpa shebang.

  • Di antara fungsi _library_ yang _membangun pada fungsi sistem_ ( man bagian 3 - man 3 exec ), hanya yang memiliki p (untuk "path", saya anggap) memiliki fallback pass-to-the-system-shell (misalnya, execlp ).

    • Implementasi pustaka GNU dari fungsi-fungsi ini dengan kode keras /bin/sh , seperti yang telah ditunjukkan @TSlivede , sedangkan yang berbasis BSD hanya menggunakan sh , dan bergantung pada sh untuk masuk $env:PATH (meskipun, anehnya, halaman man menyatakan /bin/sh ).

Seperti yang dinyatakan, untuk eksekusi _direct_ shell utama seperti POSIX ( bash , dash , ksh , dan zsh ) kembali menjalankan skrip tanpa shebang _themselves_, yang berarti mereka _not_ menggunakan varian fallback di antara fungsi library exec ; sebaliknya, perl pilihannya sendiri exec fungsi mengandalkan fallback; demikian pula, exec _builtins_ dari shell utama mirip POSIX bergantung pada fallback, kecuali pada bash .

Karena pada Unix penggunaan file skrip di belakang layar tidak diperlukan, kita dapat membuat asumsi yang sama tentang jalur shell sistem sebagai fungsi perpustakaan fallback, dan saya merekomendasikan /bin/sh lebih dari sh , untuk keamanan dan prediktabilitas:

Meskipun POSIX spec _not_ mengamanatkan lokasi sh (maksudnya, fungsi perpustakaan BSD adalah yang sesuai):

  • /bin/sh aman untuk diasumsikan, karena ini adalah lokasi standar _de facto_, paling tidak karena menulis shell Unix portabel _necessitates_ mengacu pada sh dengan path lengkapnya, mengingat bahwa baris shebang hanya mendukung _full, literal_ jalur ( #!/bin/sh ).

  • Sebaliknya, mengandalkan lokasi sh via $env:PATH dapat menjadi risiko keamanan, mengingat bahwa $env:PATH dapat dimanipulasi untuk memanggil sh .

Risiko yang sama berlaku untuk menemukan cmd.exe via $env:ComSpec , jadi mungkin cara yang lebih baik adalah memanggil fungsi GetSystemDirectory WinAPI dan menambahkan \cmd.exe ke hasilnya (kita tetap membutuhkan fallback, jika $env:ComSpec kebetulan tidak ditentukan).

/bin/sh aman untuk diasumsikan, karena ini adalah lokasi standar _de facto_, paling tidak karena menulis shell Unix portabel _necessitates_ mengacu pada sh dengan path lengkapnya, mengingat bahwa baris shebang hanya mendukung _full, literal_ jalur ( #!/bin/sh ).

Biasanya Anda mengatakan #!/usr/bin/env sh (kecuali dalam skrip sistem).

  • Biasanya, Anda _don't_: googling "#! / Bin / sh" menghasilkan sekitar 3.900.000 kecocokan, "#! / Usr / bin / env sh" menghasilkan sekitar 34.100 kecocokan.

  • Biasanya, Anda _tidak boleh_: Anda ingin menargetkan _the_ shell sistem, /bin/sh , bukan utilitas sh apa pun yang muncul pertama kali di $env:PATH .

Satu-satunya alasan untuk menargetkan sebuah executable bernama sh adalah untuk secara portabel menargetkan shell _system_ hanya-fitur-umum-umum-asumsi-POSIX-paling rendah, yaitu /bin/sh .

Biasanya, Anda _don't_: googling "#! / Bin / sh" menghasilkan sekitar 3.900.000 kecocokan, "#! / Usr / bin / env sh" menghasilkan sekitar 34.100 kecocokan.

Tidak ada cara untuk membatasi pencarian Web pada skrip pengguna, terutama karena banyak skrip pengguna tidak ditandai dapat dieksekusi sama sekali, dan bahkan jika ya, mereka mungkin mengandalkan execlp ; tetapi meskipun sebagian besar skrip pengguna mengatakan itu, kami tidak boleh menggunakan _customary_ untuk _normal_. Skrip yang akan dijalankan oleh PowerShell adalah skrip pengguna; ketika pengguna menginginkan sebuah shell, mereka memanggil sh , bukan /bin/sh , kecuali mereka paranoid.

@oising

Meneruskan baris perintah native-shell _sebagai string tunggal_ (dalam bentuk string (-literal) apa pun yang paling mudah), dan _only_ sebagai string tunggal (simpan untuk argumen baris perintah tambahan, pass-to-the-command-line yang didukung di Unix ( hanya) dibahas di atas ) - dengan asumsi Anda setuju dengan itu - terdengar seperti kesamaan.

Meneruskan baris perintah sebagai string _single_ adalah prasyarat untuk:

  • dapat menggabungkan panggilan seperti itu ke dalam pipeline _PowerShell_.
  • dapat menggabungkan variabel _PowerShell dan ekspresi_ ke dalam baris perintah native-shell.

Meneruskan satu string adalah ekspresi konseptual _direct_ dari apa yang akan dilakukan panggilan; sebaliknya, mencoba untuk entah bagaimana secara langsung menggabungkan sintaks shell yang berbeda secara langsung di PowerShell dengan argumen _individual_ (opsional kata kosong) membawa masalah yang tidak dapat diselesaikan yang menghasilkan kompromi yang membingungkan dengan batasan fundamental, yang sudah terwujud oleh --% ada.


Meskipun Anda dapat berargumen bahwa tidak terlalu penting apakah kita memilih _operator_ atau _cmdlet_ untuk meneruskan baris perintah string tunggal itu ke (kecuali untuk pertanyaan _discoverability_), saya memiliki masalah konseptual tentang penggunaan kedua & dan --% (diawali dengan & ):

  • Masalahnya adalah & : jika kita perlu meneruskan string - dikutip - yang berisi baris perintah, kita secara efektif beroperasi dalam mode _expression_, sedangkan & saat ini menyiratkan mode _argument_ (yang berarti: _individual_, mengutip hanya jika perlu). Oleh karena itu, keterlibatan & membingungkan.

  • Perhatian re --% adalah tentang asal-usul Windows saja dan semantik kacau --% sebagai simbol stop-parsing; akan sangat membingungkan jika --% sebagai simbol stop-parsing dioperasikan dalam mode _argument_ (mis.
    & /bin/ls --% dir1 dir2 ), sedangkan & --% dioperasikan dalam mode _expression_ (misalnya & --% '/bin/ls dir1 dir2 >out.txt' )


Biarkan saya mundur selangkah dan memeriksa --% , simbol stop-parsing, seperti yang saat ini diterapkan:

Itu adalah upaya untuk memecahkan dua masalah yang pada akhirnya tidak terkait (hanya untuk Windows pada saat itu):

  • (a) Kasus penggunaan yang juga berlaku untuk platform lain: Izinkan saya menggunakan kembali _command lines_ yang ditulis untuk cmd.exe / shell asli sebagaimana adanya, jadi saya tidak perlu menyesuaikannya dengan sintaks PowerShell.

  • (b) Masalah yang selalu hanya untuk Windows: Izinkan saya memanggil _rogue CLI_ (yaitu, panggilan ke aplikasi konsol eksternal _single_) yang memerlukan gaya kutipan yang sangat spesifik yang tidak dapat disediakan oleh kutipan ulang di belakang layar generik PowerShell , dengan mengizinkan saya membuat baris perintah yang akhirnya diteruskan ke WinAPI untuk CLI _verbatim_ tersebut. (Untuk membatasi pernyataan masalah ini mengasumsikan bahwa kutipan ulang PowerShell umumnya bekerja dengan baik, yang tidak pernah - itu adalah subjek # 1995).

--% diimplementasikan sebagai _conflation_ yang kacau dari upaya solusi untuk (a) dan (b), dan akhirnya tidak menyelesaikan masalah dengan benar:

  • Itu diiklankan sebagai solusi untuk (a), tetapi pada kenyataannya memiliki keterbatasan yang parah, karena _ satu-satunya fitur cmd exe yang ditiru adalah perluasan %...% -style environment-variable reference_:

    • Itu hanya mendukung perintah _single_ cmd , mengingat bahwa | (dan
      && dan || , meskipun tidak diterapkan pada saat itu) secara implisit menghentikan bagian pass-to- cmd .

    • _Single_ & - yaitu cmd s pemisah multi-perintah - _is_ dilewati, tetapi itu juga _not_ menghasilkan dukungan multi-perintah, karena - karena cmd isn ' t benar-benar terlibat - & diteruskan _verbatim ke program target_; misalnya
      echoArgs.exe --% a & b tidak menggemakan a lalu memanggil b , ini melewati argumen kata demi kata a , & , dan b menjadi echoArgs .

    • cmd karakter escape ( ^ ) dalam argumen tanpa tanda kutip tidak dihormati.

    • Sebagai akibatnya, token %...% yang merujuk ke variabel lingkungan yang ada _invariably_ diperluas; upaya untuk mencegahnya melalui ^ tidak berfungsi dengan baik (mis
      echoArgs.exe Don't expand %^USERNAME% , yang dalam cmd mencegah ekspansi _dan menghapus ^ _, mempertahankan ^ saat dipanggil dari PowerShell sebagai echoArgs.exe --% Don't expand %^USERNAME%

  • Sebagai solusi untuk (b), ini juga gagal:

    • Sama seperti dalam penggunaan (a), tidak ada kemampuan untuk memasukkan variabel dan ekspresi _PowerShell_ ke dalam perintah - kecuali jika Anda dengan canggung pertama kali mendefinisikan _aux. environment_ variable_ yang kemudian Anda referensikan melalui %...% setelah --% ; misalnya
      $env:FOO='foo'; echoArgs.exe --% %FOO%!

Solusi yang tepat untuk (a) adalah Invoke-NativeShell / ins , seperti yang dibahas di sini.

Solusi yang tepat untuk (b) adalah:

  • dukung --% hanya sebagai argumen _first_ spesial
  • dan, seperti dengan ins , mengharuskannya diikuti _ oleh satu string_ yang merupakan baris perintah pass-through _secara keseluruhan_, sekali lagi dengan kemampuan untuk memasukkan variabel _PowerShell_ dan ekspresi melalui interpolasi string (atau cara lain untuk membangun string)
  • misal msiexec --% "/i installer.msi INSTALLLOCATION=`"$loc`"" , dengan $loc berisi 'c:\foo\bar none' , akan menghasilkan baris perintah verbatim /i installer.msi INSTALLLOCATION="c:\foo\bar none" lolos, memenuhi persyaratan tidak standar msiexec bahwa dalam argumen <prop>=<value> hanya bagian <value> dikutip ganda.

Meskipun itu bukan _convenient_, itu adalah harga yang harus dibayar untuk solusi yang kuat untuk anarki yang merupakan argumen berbasis baris perintah yang diteruskan pada Windows.

@ mklement0 Terima kasih atas kesabaran dan balasannya yang bijaksana (seperti biasa.)

Jadi, saya setuju dengan sepenuh hati;

Solusi yang tepat untuk (b) adalah:

  • support -% spesial hanya sebagai argumen pertama
  • dan, seperti halnya dengan ins, memerlukannya untuk diikuti oleh satu string yang merupakan baris perintah pass-through secara keseluruhan,> - lagi-lagi dengan kemampuan untuk menggabungkan variabel dan ekspresi PowerShell dengan cara interpolasi string (atau cara lain untuk membangun string)

    • mis. msiexec -% "/ i installer.msi INSTALLLOCATION = "$loc " ", dengan $ loc berisi 'c: foobar none', akan menghasilkan baris perintah verbatim / i installer.msi INSTALLLOCATION =" c: foobar tidak ada "yang lolos, memenuhi persyaratan nonstandar msiexec yang ada di dalamnya=argumen hanyabagian dikutip ganda.

Inilah yang saya coba jelaskan sebagai solusi umum untuk (a) dan (b), kecuali saya masih belum benar-benar mengerti bahwa (a) harus ada sebagai masalah independen untuk dipecahkan? Apa yang benar-benar saya perjuangkan adalah jika (b) diimplementasikan _specific_ untuk & , mengapa itu tidak bisa menutupi (a) juga? misal: Apa ins ... memberikan & cmd --% ... tidak bisa? Dan itu tidak akan menjadi perubahan yang merusak selain tidak membiarkan & melewati --% sebagai argumen (yang tampaknya sangat tidak mungkin.) Bonus bahwa Anda tidak perlu khawatir tentang comspec, shell atau terserah. Biarkan penelepon memutuskan.

@ PowerShell / PowerShell-committee mengulas ini:

  • Ini akan menjadi fitur eksperimental untuk mendapatkan umpan balik penggunaan nyata; kita masih terbuka terhadap sigil yang sebenarnya; kami menangguhkan /bin/sh vs /bin/env sh untuk review PR
  • Kami akan melanjutkan dengan --% sebagai operator baru khusus untuk skenario "stackoverflow" di mana pengguna memotong dan menempelkan baris perintah ke PowerShell dan seharusnya berfungsi (dengan, tentu saja, operator baru yang mendahuluinya )
  • A Invoke-NativeShell cmdlet terpisah dari proposal ini dan dapat diterbitkan oleh komunitas di PowerShellGallery; juga, membutuhkan here-string tidak memecahkan masalah user experience tanpa mengetahui sebelumnya untuk membungkusnya sebagai here-string
  • Kami tidak ingin membuat perubahan yang mengganggu ke tombol --% mana pengguna yang ada mungkin bergantung pada perilaku itu
  • Pengguna yang membutuhkan perilaku streaming seperti --% harus terus menggunakan tombol itu dan menghindari karakter khusus jika diperlukan
  • Masih ada masalah penemuan bagi pengguna untuk mengetahui tentang --% (atau solusi apa pun)
  • Saat ini kami tidak melakukan perubahan pada PSReadLine untuk memodifikasi konten yang ditempelkan sebagai string di sini yang mencoba memprediksi maksud pengguna
  • Kami tidak melihat beberapa solusi yang memungkinkan skenario di sini-string vs non-di sini-string (perluasan); misalnya & --% vs --%

Saya juga ingin menambahkan bahwa, meskipun @ SteveL-MSFT dan saya menutup # 1995 pada saat yang sama dengan pembukaan yang satu ini, sebenarnya bukan maksud kami untuk mengkomunikasikan ini sebagai solusi pasti untuk masalah itu.

Menurut saya, manfaat fitur khusus ini jauh lebih signifikan daripada dampak # 1995. Saya rasa ada BANYAK contoh StackOverflow dan contoh dokumen untuk alat tercerahkan non-PS yang ingin dipotong / ditempel oleh orang-orang (termasuk saya).

Ada juga keinginan untuk memberikan pelarian yang tepat dalam bahasa PowerShell sendiri, tapi saya tidak melihat orang mencapai # 1995 di alam liar secara massal (tapi saya akan menjelaskan lebih lanjut tentang ini di sana).

  • Kami akan melanjutkan dengan --% sebagai operator baru

Maaf menyeret ini keluar, dan saya tidak mencari diskusi tambahan, tapi operator macam apa? (Saya terutama tertarik pada sintaksis.)

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

Siapa yang mendapatkan pipanya? Apa yang terjadi dengan $ ? Mirip dengan & , && , dan || .

Dalam kondisi apa, jika ada, akankah --% dapat digunakan dalam pipa PS selanjutnya?

Terima kasih.

Maaf menyeret ini keluar, dan saya tidak mencari diskusi tambahan, tapi operator macam apa? (Saya terutama tertarik pada sintaksis.)

AST bijaksana mungkin secara teknis tidak akan menjadi operator tetapi tipe AST itu sendiri. Jika diterapkan sebagai operator, itu akan menjadi operator unary.

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

Siapa yang mendapatkan pipanya? Apa yang terjadi dengan $ ? Mirip dengan & , && , dan || .

String find . -iname *$pdf -print0 | xargs -0 ls -ltr akan dikirim apa adanya ke shell asli. $a masih akan diisi, jadi Anda bisa di pipa baris berikutnya ke sesuatu.

Dalam kondisi apa, jika ada, akankah --% dapat digunakan dalam pipa PS selanjutnya?

Jika ~ di slot elemen perintah pertama ~ itu di awal pernyataan, mungkin tidak. Itulah salah satu yang menarik dari sintaks baru. Jika tidak ~ di slot pertama ~ di awal, itu akan terus berfungsi seperti sekarang.

(@ daxian-dbw @ SteveL-MSFT jika ada yang salah tolong perbaiki ❤️)

@SeeminglyScience tepat

Jika di slot elemen perintah pertama, mungkin tidak. Itulah salah satu yang menarik dari sintaks baru. Jika tidak di slot pertama, itu akan terus berfungsi seperti sekarang.

Mungkin sulit untuk meneruskan keluaran dari perintah upstream ke perintah asli yang akan dipanggil oleh --% . --% pada dasarnya hanya menyerahkan string seperti itu ke shell asli, seperti bash , tetapi output dari perintah upstream tidak bisa hanya diumpankan ke bash , tetapi harus diumpankan ke perintah asli itu sendiri, seperti find .

Menurut saya, perilaku streaming bukanlah pertimbangan untuk fitur ini karena ini terutama untuk skenario "StackOverflow". Jadi saya pikir lebih baik kita membuat --% pernyataan khusus ast, jadi jelas itu tidak akan bekerja dengan pipelines _PowerShell_.

Ahh, saya tahu ada alasan mengapa "slot elemen perintah" salah. Maksud saya di awal pernyataan. Saya akan memperbaikinya, terima kasih!

keluaran dari perintah upstream tidak bisa hanya diumpankan ke bash

Apakah _upstream_ berarti _us_? Saya pikir bisa melakukan: 'ls' | bash . Bukan hal yang sangat cerdas untuk dilakukan tetapi mungkin.

Sedang berdiskusi dengan @jpsnover tentang hal ini dan dia mengusulkan shebang #! sebagai sigil. Dalam hal ini, Anda cukup mengetik:

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

(di mana kasus kedua mengasumsikan sh ada di jalur). Dalam kasus ini, kita harus memutuskan apakah menentukan shell diperlukan atau jika kita selalu menjalankannya di bawah shell default, jadi dalam contoh ini, sh dijalankan dua kali. Namun, ada masalah dengan ini karena cara kerja file shebang hari ini. Mereka bekerja di PowerShell karena shebang diabaikan sebagai komentar. Jika kami memutuskan untuk mengabaikan baris pertama dalam skrip jika itu adalah komentar, maka kami masih memiliki masalah di shell interaktif di mana setiap set baris baru adalah skrip baru dan saat ini tidak ada cara untuk menentukan apakah skrip itu dijalankan sebagai a skrip atau secara interaktif.

Alternatifnya mungkin meminjam sintaks penurunan harga:

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

Dalam contoh ini, kami akan menggunakan sintaks pagar kode penurunan harga. Ini juga akan menyelesaikan masalah multi-baris dan akan menggunakan konsep yang tidak sepenuhnya baru. Mengingat bahwa kami masih memiliki masalah penemuan awal untuk pengguna baru, menurut saya ini tidak jauh lebih buruk karena Anda harus memiliki triple-backticks yang tertinggal.

Dalam kasus ini, ini berpotensi berhasil:

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

@ SteveL-MSFT Markdown Syntax sangat masuk akal. Jika kami dapat menentukan. jenis lain juga seperti python atau mungkin dengan ekstensi?

The shebang #! Akan mengganggu komentar yang ada.

Hal itu tampaknya terlalu rumit bagi saya, baik untuk ditangani dalam penguraian maupun bagi pengguna untuk benar-benar _menggunakan_.

Dan ya, kita tidak perlu membingungkan orang-orang dengan baris yang _harus_ menjadi komentar yang tidak berubah menjadi komentar. #Requires sudah agak aneh, lengkapnya shebang akan membingungkan orang-orang Windows, dan mungkin juga orang-orang Linux.

Saya pribadi lebih suka tidak mencampurkan fitur ini dengan shebang, itu membingungkan menurut saya.
Juga, jika kita mulai menggunakan sintaks blok kode penurunan harga, maka itu hanya masalah waktu bagi orang untuk meminta menjalankan kode bahasa arbitrer langsung di PowerShell. Saya tidak berpikir kita ingin pergi ke sana ...

Juga, jika kita mulai menggunakan sintaks blok kode penurunan harga, maka itu hanya masalah waktu bagi orang untuk meminta menjalankan kode bahasa arbitrer langsung di PowerShell.

Saya benar-benar tidak akan pernah berhenti meminta inline C # meskipun saya tahu itu ide yang buruk.

Sintaks penurunan harga tidak memperkenalkan kode bahasa arbitrer karena skrip yang disematkan akan berjalan dalam proses anak. Anda dapat menempatkan kode bahasa arbitrer di dalam @' sekarang dan tidak ada hal buruk yang terjadi.

Dalam diskusi tim dan juga dengan Jeffrey, kita tidak boleh melawan orang yang ingin menjalankan bahasa lain dalam skrip PowerShell. Seperti yang dicatat oleh @ yecril71pl , kami tidak secara langsung mendukung bahasa lain tetapi mengandalkan proses yang berbeda untuk menafsirkan dan menjalankan kode itu. Skenario di sini adalah bahwa pengguna melihat blok skrip python atau bash dan hanya ingin menggunakannya sebagaimana adanya dalam skrip PowerShell mereka. Tidak ada yang mengharuskan orang melakukan ini. Mereka dapat memutuskan untuk mentransfer skrip lain itu ke PowerShell jika mereka mau. Ini hanya memberikan opsi bagi pengguna untuk dapat memotong dan menempelkan ke PowerShell untuk menyelesaikan pekerjaan.

Kami tidak perlu mencampur proposal baris tunggal vs banyak baris karena kami dapat mendukung keduanya meskipun sisi negatifnya sekarang kami memiliki dua cara untuk melakukan hal yang sangat mirip tetapi dengan sintaks yang berbeda.

Saya lebih suka membuang hal-hal satu baris. Pulau kode asing harus menonjol, jika tidak, tidak ada yang akan mengerti apa yang sedang terjadi.

@ yecril71pl Saya sendiri cenderung ke arah itu karena dari sudut pandang penemuan, sintaks penurunan harga menurut saya akan lebih mudah dikenali, tetapi itu mungkin saja karena saya sering menulis penurunan harga. Saya juga berharap bahwa banyak contoh skrip mungkin multi-baris daripada hanya satu baris karena mereka mengharapkan beberapa status dipertahankan di mana setiap baris akan menjadi proses independen.

Dalam diskusi tim dan juga dengan Jeffrey, kita tidak boleh melawan orang yang ingin menjalankan bahasa lain dalam skrip PowerShell.

Benar-benar 100%, tetapi itu tidak berarti itu perlu dibangun langsung ke dalam bahasa.

Seperti yang dicatat oleh @ yecril71pl , kami tidak secara langsung mendukung bahasa lain tetapi mengandalkan proses yang berbeda untuk menafsirkan dan menjalankan kode itu. Skenario di sini adalah bahwa pengguna melihat blok skrip python atau bash dan hanya ingin menggunakannya sebagaimana adanya dalam skrip PowerShell mereka.

Itu sudah bisa dilakukan dengan string di sini kan? Bisakah Anda menjelaskan sedikit tentang manfaat apa yang diberikannya dibandingkan metode yang ada?

Juga mengapa berhenti di python dan bash? Mengapa bukan C #, CIL, C ++?

Tidak ada yang mengharuskan orang melakukan ini. Mereka dapat memutuskan untuk mentransfer skrip lain itu ke PowerShell jika mereka mau. Ini hanya memberikan opsi bagi pengguna untuk dapat memotong dan menempelkan ke PowerShell untuk menyelesaikan pekerjaan.

Saya tidak menentang ini karena saya pikir saya akan dipaksa untuk menggunakannya. Saya tidak menyukainya karena akan sulit untuk mempertahankan dari perspektif bahasa, mimpi buruk bagi editor, dan pada akhirnya mendorong skrip yang tidak dapat dibaca kecuali Anda menguasai beberapa bahasa.


Sungguh meskipun ini adalah konsep yang sangat berbeda dari topik asli utas ini dengan implikasi yang jauh lebih luas. Saya akan merekomendasikan membuat masalah baru untuk itu.

Itu sudah bisa dilakukan dengan string di sini kan? Bisakah Anda menjelaskan sedikit tentang manfaat apa yang diberikannya dibandingkan metode yang ada?

Editor kode universal akan dapat mendeteksi dan menghiasnya dengan tepat, sedangkan tidak ada yang bisa dilakukan dengan @' karena editor tidak tahu apa yang ada di dalamnya.

Juga mengapa berhenti di python dan bash? Mengapa bukan C #, CIL, C ++?

Karena mereka bukan bahasa skrip?

Editor kode universal akan dapat mendeteksi dan menghiasnya dengan tepat, sedangkan tidak ada yang bisa dilakukan dengan @' karena editor tidak tahu apa yang ada di dalamnya.

Seorang editor dapat mengetahui bahwa bash -c @' berisi bash semudah pagar kode. Juga bagian yang menantang bukanlah menentukan bahasa apa bagian dari kode itu, itu menyulap server bahasa dan penyorot sintaks. Satu-satunya cara itu akan bekerja tanpa investasi waktu dan usaha yang signifikan akan membuatnya seperti itu adalah string di sini.

Karena mereka bukan bahasa skrip?

C # dan C ++ keduanya memiliki subset berorientasi skrip. Bahkan jika mereka tidak melakukannya, "bahasa skrip" bersifat subjektif tanpa definisi yang sebenarnya. Ini tidak membantu sebagai batas definitif untuk apa yang akan dan tidak akan dipertimbangkan untuk dimasukkan.

C # dan C ++ keduanya memiliki subset berorientasi skrip. Bahkan jika mereka tidak melakukannya, "bahasa skrip" bersifat subjektif tanpa definisi yang sebenarnya.

Bahasa adalah bahasa skrip (berdiri sendiri) ketika Anda biasanya memanggil interpet options… script arguments… dan panggilan itu tidak menyisakan apa pun kecuali yang dimaksudkan untuk ditinggalkan, tidak termasuk hal-hal sementara dan pribadi untuk penerjemah. Ini juga berarti bahwa biasanya memerlukan salinan penerjemah untuk dijalankan. Ada bahasa skrip tertanam yang tidak dapat Anda jalankan dengan cara ini.

@Tokopedia

Itu sudah bisa dilakukan dengan string di sini kan? Bisakah Anda menjelaskan sedikit tentang manfaat apa yang diberikannya dibandingkan metode yang ada?

Orang dapat menggunakan string di sini hari ini atau mereka dapat melarikan diri dari semua argumen yang diteruskan ke perintah asli jika mereka dapat menemukan cara untuk melakukannya dengan benar. Maksudnya di sini adalah untuk mempermudah pengguna baru untuk skenario potong-dan-tempel (Stackoverflow).

Juga mengapa berhenti di python dan bash? Mengapa bukan C #, CIL, C ++?

Skenario yang didukung di sini adalah blok teks yang diteruskan ke perintah asli. Bahasa apa pun dapat didukung jika mendukung konvensi panggilan itu. Tidak ada proposal untuk membuat file sumber sementara dan telah dikompilasi.

Saya tidak menentang ini karena saya pikir saya akan dipaksa untuk menggunakannya. Saya tidak menyukainya karena akan sulit untuk mempertahankan dari perspektif bahasa, mimpi buruk bagi editor, dan pada akhirnya mendorong skrip yang tidak dapat dibaca kecuali Anda menguasai beberapa bahasa.

Tidak ada harapan bahwa Anda mendapatkan pewarnaan sintaks bahasa campuran. Setiap skrip bertingkat dari bahasa lain hanya akan dibuat monoton.

Sungguh meskipun ini adalah konsep yang sangat berbeda dari topik asli utas ini dengan implikasi yang jauh lebih luas. Saya akan merekomendasikan membuat masalah baru untuk itu.

Implementasi yang diusulkan berbeda dari masalah aslinya, tetapi masalahnya sama yaitu skenario cut-and-paste dan "hanya bekerja".

Orang dapat menggunakan string di sini hari ini atau mereka dapat melarikan diri dari semua argumen yang diteruskan ke perintah asli jika mereka dapat menemukan cara untuk melakukannya dengan benar. Maksudnya di sini adalah untuk mempermudah pengguna baru untuk skenario potong-dan-tempel (Stackoverflow).

Benar tapi bagaimana sebenarnya lebih mudah? Saya mengerti bahwa itu subyektif tetapi ini tampaknya tidak jauh berbeda bagi saya:

~~~ PowerShell
$ a = `` pesta
Temukan . -iname * $ pdf -print0 | xargs -0 ls -ltr

~~~

vs

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

Mereka tampak hampir sama dengan pengecualian bahwa yang terakhir secara signifikan lebih jelas tentang apa yang akan terjadi.

Skenario yang didukung di sini adalah blok teks yang diteruskan ke perintah asli. Bahasa apa pun dapat didukung jika mendukung konvensi panggilan itu. Tidak ada proposal untuk membuat file sumber sementara dan telah dikompilasi.

Nah C # tidak membutuhkan file sumber sementara. Mungkin juga bukan CIL (tidak tahu tentang C ++). Either way meskipun pagar kode yang secara ketat menjadi gula sintaksis untuk memanggil sebuah executable (misalnya bash / python / cmd) membingungkan saya. Pagar kode menyiratkan dukungan bahasa imo.

Tidak ada harapan bahwa Anda mendapatkan pewarnaan sintaks bahasa campuran. Setiap skrip bertingkat dari bahasa lain hanya akan dibuat monoton.

Ini masih akan menjadi mimpi buruk bagi parser berbasis tmLanguage. Mereka hampir tidak bisa menangani sintaks yang mereka harapkan atm. Lebih dari itu, jika itu masalahnya, saya tidak mengerti mengapa itu berbeda dari string di sini.

Implementasi yang diusulkan berbeda dari masalah aslinya, tetapi masalahnya sama yaitu skenario cut-and-paste dan "hanya bekerja".

Adil tapi kami sudah 145 komentar untuk membahas solusi yang diusulkan sebelumnya. Terutama karena utas ini sudah sampai pada kesimpulan, Anda mungkin akan melihat lebih banyak keterlibatan dalam utas baru yang berdedikasi.

Nah C # tidak membutuhkan file sumber sementara. Mungkin juga bukan CIL (tidak tahu tentang C ++). Either way meskipun pagar kode yang secara ketat menjadi gula sintaksis untuk memanggil sebuah executable (misalnya bash / python / cmd) membingungkan saya. Pagar kode menyiratkan dukungan bahasa imo.

Saya hanya ingin menggemakan komentar @SeeminglyScience tentang ini. Kita dapat menjalankan skrip C # tanpa melibatkan kompilasi dengan pustaka Microsoft.CodeAnalysis.CSharp.Scripting . Itulah yang digunakan dotnet-interactive di kernel C # Jupyter. Jadi mungkin tidak masuk akal bagi pengguna untuk meminta skrip C # atau bahkan dukungan skrip F # dengan sintaks seperti itu.

Anda dapat mengatakan bahwa sintaks kode pagar di PowerShell adalah untuk memanggil perintah asli, yang secara teoritis memungkinkan ini:

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

tapi berbeda dengan pemahaman pengguna tentang penurunan harga, yang, seperti yang dikatakan @SeeminglyScience , menyiratkan dukungan bahasa. Menggunakan sintaks yang mirip dengan semantik berbeda menurut saya membingungkan.

yang secara teoritis memungkinkan hal ini

Anda meletakkan skrip di dalam, bukan argumen, dan skrip tersebut setara dengan aliran input. Selain itu, jika ini dimaksudkan untuk memberikan dukungan SO, jalur lengkap tidak boleh diizinkan.

Anda meletakkan skrip di dalam, bukan argumen, dan skrip tersebut setara dengan aliran input

Skrip adalah argumen untuk bash / cmd / python.

Selain itu, jika ini dimaksudkan untuk memberikan dukungan SO, jalur lengkap tidak boleh diizinkan.

Kemudian alihkan untuk contoh ini:

~ PowerShell$ a = ipconfig /all ~

Atau tambahkan exe arbitrer ke jalur terlebih dahulu.

Anda meletakkan skrip di dalam, bukan argumen, dan skrip tersebut setara dengan aliran input

Skrip adalah argumen untuk bash / cmd / python.

Tak satu pun dari mereka mengizinkan untuk melewatkan skrip sebagai argumen posisi. CMD bahkan tidak mengizinkan file batch.

Selain itu, jika ini dimaksudkan untuk memberikan dukungan SO, jalur lengkap tidak boleh diizinkan.

Kemudian alihkan untuk contoh ini:

$ a = `` ipconfig
/semua

Itu tidak akan berhasil.

Sepertinya kita akan membuat banyak sekali kasus khusus dengan sangat sewenang-wenang agar ide penurunan harga ini berhasil.

Juga, alasan utama ini bahkan didukung di penurunan harga adalah untuk penyorotan sintaks. Itu akan menjadi permintaan konstan jika kita menambahkan sesuatu seperti ini ke dalam bahasa.

Ini bukanlah solusi yang efektif.

Sedang berdiskusi dengan @jpsnover tentang hal ini dan dia mengusulkan shebang #! sebagai sigil

hanya untuk menambahkan 2 sen saya, saya pikir itu kesalahan untuk memulai kembali diskusi ini setelah solusi diumumkan. dan secara pribadi saya tidak menyukai sintaks shebang dan penurunan harga (dan keduanya melanggar perubahan).

Saya tidak keberatan memulai kembali diskusi jika seseorang telah menemukan sesuatu yang terbukti lebih baik. Memang lebih baik melakukannya sekarang daripada setelah fitur tersebut dikirimkan. Saya hanya tidak berpikir #! atau pendekatan penurunan harga adalah solusi yang lebih baik untuk memasok string baris perintah "un-PowerShell-adulterated" ke exe asli. Mungkin aku hanya perlu mencobanya untuk membiasakannya tapi reaksi pertamaku adalah ... um, eew.

_Jika kita (dan PowerShell) tahu bahwa kita menjalankan executable asli, mengapa kita perlu "memanggil operator asli" sama sekali? _

Jika PowerShell mengurai string input dan mendapatkan CommandAst, maka PowerShell akan menemukan perintah tersebut.
Jika perintah adalah perintah asli, PowerShell mengonversi ast ke NativeCommandProcessor.
Kita dapat mengimplementasikan baru (eksperimental NativeCommandProcessor) untuk kasus yang akan mengurai ulang tingkat Ast (itu adalah string input) sehingga untuk mendapatkan nama / jalur yang dapat dieksekusi asli dan sisa string sebagai argumen atau argumen oleh aturan OS.

Jika pengguna ingin menyalin-tempel dari shell, ia harus mengetik "cmd"atau" bash"- itu akan berfungsi tanpa mengedit.
Jika pengguna ingin menyalin-tempel baris perintah asliakan bekerja terlalu seperti g++ timer.cpp @conanbuildinfo.args -o timer --std=c++11 .

Jika pengguna ingin copy-paste dari shell

Kami memiliki Get-/Set-Clipboard untuk itu.

untuk kasus yang akan mengurai ulang tingkat Ast (yaitu string input) sehingga mendapatkan nama / jalur yang dapat dieksekusi asli dan sisa string sebagai argumen atau argumen oleh aturan OS.

Pemikiran saya di sini adalah melakukan ini Anda juga:

  • Mengurai perintah AST secara tidak efisien, hanya untuk mem-parsing ulang tingkat tersebut nanti sebagai string dan membuang AST asli, ATAU
  • Anda mengambil AST dan mencoba mereformasi kembali menjadi string (seperti yang dilakukan NativeCommandProcessor saat ini), tetapi dengan melakukan hal itu akan hilang.

Jadi sebagai gantinya kita perlu mempertahankan string dari awal. Nah, menurut saya bisa dibilang PowerShell sudah memiliki tiga macam string token, namun request utama dalam pembahasan kali ini sepertinya tidak ingin luput dari berbagai hal. Setiap string harus dapat keluar dari terminatornya, tetapi solusi yang dibahas di sana tampaknya menggunakan baris baru sebagai terminator dan tidak dapat keluar dari baris baru (selalu ada titik koma).

Saya tidak sepenuhnya terikat dengan terminator hanya baris baru, tetapi tampaknya itu satu-satunya solusi untuk tidak ingin melarikan diri dari apa pun. Pada dasarnya itu akan membuat "operator panggilan asli" tokenise mirip dengan bagaimana komentar baris hari ini - dari operator ke akhir baris adalah string yang diteruskan ke "shell asli".

Begitu:

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

akan tokenise sebagai:

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

(Perhatikan bahwa kami bahkan mengirim spasi langsung setelah --% ke shell asli, karena string dimulai tepat setelah --% )

Kemudian token ini dibungkus dengan AST yang sangat sederhana, seperti:

// 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; }
}

Kemudian, setelah ini dikompilasi dan dikirim ke pipa, ini menggunakan prosesor perintah asli baru untuk mengirim string secara langsung sebagai argumen ke shell asli.

Sementara itu semua tampak dapat diterapkan, beberapa pertanyaan dalam pikiran saya adalah:

  • Apakah shell asli dapat dikonfigurasi? Jika tidak, bagaimana kita membenarkannya? Jika demikian, apakah harus eksplisit sebagai bagian dari sintaks (memperumit sintaks), atau diterapkan sebagai variabel preferensi (membuatnya lebih sulit untuk ditemukan dan dikelola)?
  • Apakah penerapan seperti itu akan mudah ditemukan dan tidak membingungkan orang? Akankah pengguna memahami betapa sedikit yang dilakukan PowerShell di sini, atau apa yang terjadi ketika mereka menggunakan | atau & atau bahkan string?
  • Berapa banyak skenario yang akan dilayani oleh string verbatim baris tunggal di sini? Apakah kita akan menerapkan ini hanya untuk mengetahui bahwa banyak orang menginginkan pemanggilan multi-baris? Apakah kebutuhan untuk menghindari melakukan sesuatu seperti meloloskan diri dari kutipan tunggal cukup besar untuk menambahkan batasan ini?
  • Ini sepertinya skenario yang sangat spesifik untuk sintaks bahasa baru. Jika kita membuat sintaks string verbatim baru, mengapa kita menggabungkannya langsung ke konsep pemanggilan asli? Jika kita membuat mekanisme pemanggilan baru, mengapa kita menggabungkannya langsung ke konsep shell lain? Sintaks yang baik dan konstruksi bahasa yang baik menulis, baik secara sintaksis maupun fungsional, dan mencoba untuk tidak terlalu banyak memanggang ke dalam bahasa itu sendiri (alih-alih menyediakan platform elemen bagi pengguna untuk dirakit sebagai program mereka) - apakah sintaks panggilan asli yang kami usulkan memenuhi standar untuk sintaks dasar baru yang akan disusun menjadi program? Adakah pendekatan alternatif yang lebih baik yang dapat kita ambil untuk menyelesaikan masalah ini dengan cara yang sederhana, tetapi masih memungkinkan kita untuk menjaga blok penyusun tidak terhubung sehingga dapat disusun untuk memecahkan masalah lain?
  • Akankah shell lain atau bahasa lain menerapkan ini atau sudahkah mereka? Di tingkat sintaks, atau di tingkat lain? Jika ya, bagaimana caranya?

Pemikiran saya di sini adalah melakukan ini Anda juga

@rjmholt CommandAst memiliki properti Extent dengan string input. Penguraian ulang semudah memisahkan spasi pertama di Windows atau dipisahkan dengan spasi di Unix. Jadi saya berharap kami tidak kehilangan apa-apa dalam string dan mendapatkan performa yang bagus.

Namun ini diterapkan, saya pikir kita perlu serangkaian kasus penggunaan untuk diuji. Izinkan saya "mengusulkan" yang berikut:

  • Kasus penggunaan 1: Saya ingin satu pemanggilan literal exe (tanpa interpolasi) bekerja tanpa mengetahui tentang aturan kutipan / pelolosan misalnya: g++ timer.cpp @conanbuildinfo.args -o timer --std=c++11 . Solusi saat ini adalah mencari tahu apa yang akan dikutip e..g: g++ timer.cpp '@conanbuildinfo.args' -o timer --std=c++11 Contoh yang lebih rumit mungkin menyertakan baris perintah yang mencakup beberapa baris misalnya:
tar -cvpzf /share/Recovery/Snapshots/$(hostname)_$(date +%Y%m%d).tar.gz \
    --exclude=/proc \
    --exclude=/lost+found 

Solusi saat ini (tukar backtick untuk \ ) misalnya:

tar -cvpzf /share/Recovery/Snapshots/$(hostname)_$(date +%Y%m%d).tar.gz `
    --exclude=/proc `
    --exclude=/lost+found
  • Use case 1a: Saya ingin satu pemanggilan exe dengan interpolasi PS berfungsi misalnya: g++ $CppFile @conanbuildinfo.args -o timer --std=c++11 . Solusi saat ini adalah untuk mencari tahu apa yang harus dikutip (tunggal atau ganda) dan apa yang harus dihindari e..g: g++ $CppFile '@conanbuildinfo.args' -o timer --std=c++11 Contoh yang lebih rumit mungkin termasuk baris perintah yang mencakup beberapa baris misalnya:
tar -cvpzf "/share/Recovery/Snapshots/${ComputerName}_`$(date +%Y%m%d).tar.gz" \
    --exclude=/proc \
    --exclude=/lost+found 

Solusi saat ini, kutip ganda argumen pertama, tukar backtick untuk \ dan hindari $ di awal `$ (date + ...).

  • Use case 2: Saya ingin menjalankan perintah pipelined literal di shell lain misalnya: ps -o pid,args -C bash | awk '/running_script/ { print $1 }' dan wsl ls $foo && echo $PWD . _Saya tidak yakin apakah ini perlu menjadi kasus penggunaan terpisah dari yang sebelumnya._ Solusi saat ini adalah mengutip perintah bash misalnya: bash -c 'ps -o pid,args -C bash | awk ''/-bash/ { print $1 }''' . Kasus penggunaan ini mungkin termasuk string multiline juga, misalnya:
ps -o pid,args -C bash | \
awk '/running_script/ { print $1 }'
  • Use case 2a: Saya ingin menjalankan perintah pipelined di shell lain dengan beberapa interpolasi PS - apakah ini use case?

  • Use case 3: Saya perlu npm run $scriptName untuk terus bekerja yaitu menginterpolasi variabel . (ini mungkin implisit dan tidak perlu dinyatakan).

Ada pertanyaan apakah harus ada kasus penggunaan untuk string interpolating yaitu g++ $CppFile @conanbuildinfo.args -o timer --std=c++11 atau apakah kita hanya menyepaknya dan mengatakan bahwa aturan pelolosan saat ini mencakup ini?

Ini mungkin bukan kasus penggunaan yang benar (atau semua), tetapi saya pikir akan sangat membantu untuk mendokumentasikan kasus penggunaan dan dapat merujuknya saat mendiskusikan fitur ini, jika tidak, mudah tersesat dalam cara fitur tersebut menangani (atau tidak ) kasus penggunaan pelanggan.

Juga, kasus penggunaan kedua menurut saya memerlukan "permintaan shell". Saya tidak yakin yang pertama melakukannya. Sepertinya exe bisa dipanggil secara langsung.

@rkeithhill Bisakah Anda menambahkan solusi yang ada untuk kelengkapan di posting Anda sebelumnya?

@oising , saya sangat menghargai tanggapan bijaksana Anda.

Apa yang ins ... berikan yang & cmd --% ... tidak bisa?

--% dalam bentuknya saat ini, _parameter_ (simbol) - yang perilakunya saya anggap ingin kita pertahankan - tidak dapat digunakan untuk cmd /c --% , karena tidak mendukung _multi-command_ cmd baris perintah (atau ^ sebagai karakter escape.), mengingat bahwa | tidak diberi tanda kutip akan diinterpretasikan sebagai operator pipa _PowerShell's_ dan & diteruskan kata demi kata.
Hal yang sama berlaku pada Unix, di mana --% umumnya hampir tidak berguna, dan dengan sh -c gagal sama sekali, karena sh mengharapkan baris perintah sebagai argumen _single_ (mis., sh -c --% echo hi menghasilkan baris kosong, karena echo saja dijalankan sebagai perintah).

ins , dengan persyaratannya untuk membatasi baris perintah pass-through dengan meneruskannya _sebagai satu string_ memecahkan masalah ini, dan, seperti yang dinyatakan, juga memungkinkan penggunaan interpolasi string untuk memasukkan variabel _PowerShell_ dan nilai ekspresi.

Dan yang terakhir membawa kita pada mengapa --% _statement_ yang diusulkan adalah jalan _dead-end_ :

  • Ada _tidak ada jalur transisi_ dari menjalankan baris perintah yang sudah ada _seperti apa adanya_ untuk memasukkan variabel _PowerShell_ dan nilai ekspresi ke dalamnya.

    • Satu-satunya cara - tidak jelas dan tidak praktis - untuk mencapai ini adalah dengan mendefinisikan _auxiliary environment variable_ yang menyimpan nilai-nilai PowerShell yang menarik dan yang kemudian dapat Anda referensikan (shell-tepat dengan %...% atau $... ) di baris perintah asli.
  • Anda merasa canggung karena tidak dapat memasukkan pernyataan --% ke dalam pipeline PowerShell yang lebih besar.

    • Perhatikan bahwa ada alasan _non_-cut-and-paste yang sah untuk memanggil shell asli, di mana Anda mungkin mengharapkan integrasi ini; khususnya, meneruskan _raw byte data_ melalui pipeline (perantara) dan mengirim _string tanpa trailing newline_ memerlukan penggunaan pipa native - lihat jawaban SO ini untuk contoh kehidupan nyata.
  • Ada juga kecanggungan dari --% _parameter_ yang hampir tidak berguna di Unix, yang memperkenalkan asimetri yang aneh: jika --% _statement_ juga berfungsi di Unix, mengapa tidak --% _parameter_ ? (misalnya,
    /bin/echo --% 'hi "noon"' menghasilkan kata demi kata 'hi noon' (bukan yang diharapkan hi "noon" ), karena echo menerima _two_ argumen, kata demi kata 'hi dan noon' , dengan tanda kutip tunggal dipertahankan sebagai data dan tanda kutip ganda dihapus).


ins , sebagai alternatif yang disarankan untuk pernyataan --% , idealnya adalah _convenience wrapper_ sekitar cmd /c dan sh -c , tetapi sebenarnya _required_:

  • Setidaknya _temporently_ di Unix, selama # 1995 tidak diperbaiki, karena memanggil sh -c '...' secara langsung saat ini tidak meneruskan argumen dengan " disematkan melalui dengan benar.

  • _Invariably_ di Windows, karena Anda harus meneruskan baris perintah _as-is_ ke cmd melalui parameter lpCommandLine dari CreateProcess (yang tidak dapat dilakukan oleh parameter --% karena dibatasi pada perintah _one_); sebagai alternatif mencoba untuk melewatkan baris perintah sebagai string _single_ yang diapit dalam "..." secara keseluruhan lagi tidak berfungsi dengan baik karena # 1995.


Masalah dengan penerusan _argument_ dapat dihindari dengan menyediakan baris perintah untuk mengeksekusi _via stdin_ (yang dapat dan harus didukung oleh ins ), yaitu untuk _pipe_ teks baris perintah / skrip ke shell yang dapat dieksekusi:

  • Di Unix, ini berfungsi dengan baik, karena meneruskan kode melalui _stdin_ ke sh pada dasarnya sama dengan meneruskan file _script_ untuk eksekusi (seperti sh -c '<code>' is ):
PSonUnix> @'
echo '{ "foo": "bar" }' | cat -n
'@ | sh

     1  { "foo": "bar" }
  • Sayangnya, pada Windows cmd tidak menangani input seperti itu dengan baik: ia mencetak logonya dan menggemakan setiap perintah sebelum dieksekusi, bersama dengan string prompt:
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>

Sayangnya, PowerShell sendiri menunjukkan perilaku yang sama tidak membantu: lihat # 3223


Sama seperti sh dan semua shell utama seperti POSIX ( dash , bash , ksh , zsh ), sebagian besar bahasa skrip _do_ dengan benar mendukung masukan stdin-as-script, seperti python , node , ruby , dan perl .

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

hi

Untuk memasukkan variabel _PowerShell_ dan nilai ekspresi, Anda kembali memiliki opsi untuk menggunakan interpolasi / penggabungan string:

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

bar

atau menggunakan fitur penerusan argumen dari penerjemah:

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

bar

Saya harap hal di atas menjelaskan bahwa _tidak ada kebutuhan untuk sintaks khusus sama sekali - baik pernyataan --% , maupun pernyataan #! , atau blok kode penurunan harga - yang semuanya lagi-lagi tidak akan kekurangan kemampuan untuk memasukkan nilai-nilai dari skrip PowerShell panggilan.

Adapun konfigurasi native shell yang akan digunakan: Untuk prediktabilitas, saya rasa kami tidak harus menawarkannya; pengguna yang ingin menargetkan shell yang berbeda cukup menyalurkan baris perintah ke file executable spesifik shell tersebut atau, setelah # 1995 diperbaiki, berikan sebagai argumen.

  • Variasi yang bisa diperdebatkan adalah menargetkan /bin/bash (dengan fallback (tidak mungkin) ke /bin/sh ) - sementara orang akan berharap bahwa baris perintah yang diterbitkan hanya mengandalkan fitur yang diamanatkan POSIX, baris perintah dengan Bash-isms (fitur non-POSIX yang tidak diharapkan untuk mendukung semua implementasi /bin/sh ) kemungkinan besar tersedia, mengingat prevalensi bash .

@joeya

Menurut saya, manfaat fitur khusus ini jauh lebih signifikan daripada dampak # 1995.

Saya merasa heran bahwa kami menghabiskan banyak upaya seperti yang kami miliki untuk membuat fitur potong-dan-tempel ini - terutama untuk kenyamanan _interactive_ - warga kelas satu (canggung, terbatas fitur), sedangkan ketidakmampuan mendasar PowerShell untuk lulus kosong argumen dan argumen dengan karakter " disematkan.

tapi saya tidak melihat orang mencapai # 1995 di alam liar secara massal

Ya, dan untuk alasan yang telah saya bahas sebelumnya _Anda akan semakin sering melihatnya_.

Sekali lagi, saya berpendapat shell yang melakukan hal berikut, seperti yang dilakukan PowerShell saat ini, memiliki masalah serius :

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

{ foo: bar }

@rjmholt CommandAst memiliki properti Extent dengan string input. Penguraian ulang semudah memisahkan spasi pertama di Windows atau dipisahkan dengan spasi di Unix. Jadi saya berharap kami tidak kehilangan apa-apa dalam string dan mendapatkan performa yang bagus.

Ya, saya memahami hasil imbang di sana, dan mungkin alokasi AST dalam skenario itu tidak buruk (meskipun saya berpendapat bahwa bahasa seharusnya tidak menghasilkan alokasi yang tidak perlu untuk sintaks sederhana). Tetapi yang harus Anda lakukan adalah membayangkan input yang dilihat bash / cmd sebagai string dan PowerShell tidak mulai mengalami masalah:

Tidak mengurai dengan PowerShell saat ini:

--% my_command "\" "

Parsing, tetapi membagi dengan spasi memberikan hasil yang salah:

--% my_command "\"    "\"

(Kita harus mengirim 4 spasi dalam string, tetapi PowerShell melihat dua string dipisahkan dalam larik)

@rjmholt , semua pertanyaan bagus di bagian bawah komentar Anda di

Saya telah menjawab pertanyaan tentang apa yang dapat dieksekusi shell asli untuk digunakan dalam komentar saya

Akankah shell lain atau bahasa lain menerapkan ini atau sudahkah mereka? Di tingkat sintaks, atau di tingkat lain? Jika ya, bagaimana caranya?

Saya tidak mengetahui ada bahasa lain yang melakukan ini pada tingkat sintaks tanpa menggunakan pembatas _explicit_ dan mengizinkan _interpolation_.
Misalnya, perl memiliki `...` untuk menjalankan perintah shell, jadi Anda dapat menjalankan perintah berikut dari skrip di Unix, misalnya:
my $foo='/'; print `ls $foo | cat -n`

Aspek kuncinya adalah penggunaan pembatas eksplisit dan kemampuan untuk memasukkan nilai dari pemanggil - keduanya hilang dari proposal saat ini untuk pernyataan --% .

Seperti yang dinyatakan sebelumnya, kami _dapat_ menggunakan pendekatan ini untuk _operator_ baru (atau semacam sintaks berbasis pembatas, interpolasi opsional), tetapi saya rasa itu tidak layak, mengingat itu
ins "ls $foo | cat -n" (atau dengan varian string di sini) akan dilakukan, tanpa membebani bahasa dengan kompleksitas tambahan.

perl menawarkan solusi tingkat sintaks (yang tepat) _karena ia sendiri bukan shell_ tetapi ingin membuat panggilan shell senyaman mungkin.

Sebaliknya, kami _are_ shell (juga), dan menawarkan pemanggilan gaya shell _directly_, tanpa sintaks tambahan (meskipun saat ini cacat - lihat # 1995).
Menyediakan sintaks khusus untuk membuat pemanggilan _a shell's_ yang berbeda semudah mungkin tampaknya tidak diperlukan.

@tokopedia

_Jika kita (dan PowerShell) tahu bahwa kita menjalankan executable asli, mengapa kita perlu "memanggil operator asli" sama sekali? _

Jika PowerShell mengurai string input dan mendapatkan CommandAst, maka PowerShell akan menemukan perintah tersebut.
Jika perintah adalah perintah asli, PowerShell mengonversi ast ke NativeCommandProcessor.
Kita dapat mengimplementasikan baru (eksperimental NativeCommandProcessor) untuk kasus yang akan mengurai ulang tingkat Ast (itu adalah string input) sehingga untuk mendapatkan nama / jalur yang dapat dieksekusi asli dan sisa string sebagai argumen atau argumen oleh aturan OS.

Jika pengguna ingin menyalin-tempel dari shell, dia harus mengetik "cmd" atau "bash" - yang akan berfungsi tanpa mengedit.
Jika pengguna ingin menyalin-tempel baris perintah asli akan berfungsi juga seperti g++ timer.cpp @conanbuildinfo.args -o timer --std=c++11 .

Tapi tunggu, bukankah Anda tidak akan pernah bisa menggunakan sintaks PowerShell apa pun dengan perintah asli jika kami melakukan semua itu? Jadi seperti sc.exe query $serviceName akan melewatkan $serviceName sebagai string literal?

Tapi tunggu, bukankah Anda tidak akan pernah bisa menggunakan sintaks PowerShell apa pun dengan perintah asli jika kami melakukan semua itu? Jadi seperti sc.exe query $serviceName akan melewatkan $serviceName sebagai string literal?

Opsi --% tidak dimaksudkan untuk memenuhi kebutuhan itu.

sc.exe query $serviceName ditangani oleh &"<cmd>"

Opsi --% tidak dimaksudkan untuk memenuhi kebutuhan itu.

sc.exe query $serviceName ditangani oleh &"<cmd>"

Ya yang pasti, saya tidak berpikir itu yang dimaksud @iSazonov . Saya membaca bahwa seolah-olah mereka menyarankan perubahan umum tentang cara kerja pengikatan parameter untuk perintah asli.

Ya yang pasti, saya tidak berpikir itu yang dimaksud @iSazonov . Saya membaca bahwa seolah-olah mereka menyarankan perubahan umum tentang cara kerja pengikatan parameter untuk perintah asli.

Tuhan, saya harap tidak.

Tuhan, saya harap tidak.

Eh terkadang saat Anda sedang melakukan brainstorming tentang abstrak, mudah untuk melupakan yang sudah jelas. Maksud saya bersikap adil, kita semua membacanya dan segera mulai memikirkan implementasi tanpa menyadari betapa hal itu akan merusaknya.

Atau saya kehilangan sesuatu yang jelas dan sama sekali bukan itu yang diusulkan 😁

@essentialexch , agar jelas, re:

sc.exe query $serviceName ditangani oleh &"<cmd>"

& "<cmd>" hanya berfungsi jika <cmd> mengevaluasi ke perintah saja _name atau path_, _tidak termasuk argumen_ - argumen harus disampaikan secara terpisah, satu per satu - dan mereka tidak perlu "...." mengutip untuk referensi variabel yang akan diperluas (misalnya,
$exe = 'findstr'; & "where.exe $exe" gagal karena desain; harus & "where.exe" $exe (tanda kutip ganda opsional di sini; jika dihilangkan, & juga opsional))

Ya yang pasti, saya tidak berpikir itu yang dimaksud @iSazonov . Saya membaca bahwa seolah-olah mereka menyarankan perubahan umum tentang cara kerja pengikatan parameter untuk perintah asli.

Proposal saya adalah memperbaiki # 1995 (dengan perubahan yang menghancurkan) sesederhana mungkin. Penyebab interpolasi tidak bekerja. Sebab itu bukan proposal final - ini mendemonstrasikan bagaimana kami dapat menerapkan perbaikan dalam hitungan menit. Dan terutama demo bahwa kita tidak memerlukan operator panggilan asli sama sekali seperti yang ditunjukkan @ mklement0 juga.

Parsing, tetapi membagi dengan spasi memberikan hasil yang salah:

@rjmholt Ya, tapi saya pikir Anda menangkap idenya.
Anak pertama dari CommandAst adalah StringConstantExpressionAst dengan perintah asli sebagai BareWord. Kita dapat memotong kata kosong dari CommandAst Extent dan mendapatkan daftar parameter tanpa perubahan ast-s. Tapi kita bisa menambahkan ast baru untuk menyimpan daftar parameter juga.
Saya meluangkan waktu untuk penjelasannya karena di bawah ini saya ingin meringkas diskusi dan saya merasa kita perlu menerapkan beberapa peningkatan yang terlihat rumit tetapi saya merasa itu dapat diterapkan secara sederhana dan __dengan memilih keluar yang mudah untuk kompatibilitas ke belakang__.


Saya yakin maksud @ SteveL-MSFT dari proposal awal adalah untuk menghindari perubahan yang dapat merusak.
Saya setuju dengan @TSlivede dan @ mklement0 bahwa diskusi ini menunjukkan bahwa sintaks baru tidak diperlukan karena tidak menyelesaikan semua masalah _fundamental_ seperti # 1995 dan # 12975. Di sisi lain, ini menambah kompleksitas pada bahasa, sementara kami ingin, sebaliknya, untuk _simplify_ bekerja dengan aplikasi asli.

__Satu-satunya cara untuk maju adalah dengan membuat perubahan besar atau lebih .__ (Setelah itu, operator atau cmdlet baru mungkin juga berguna dalam beberapa skenario.)


Kita harus mulai dengan meringkas kasus penggunaan dan harapan pengguna.
Lihat postingan bagus @rkeithhill di atas

  1. Pengguna ingin mengaktifkan / menonaktifkan interpolasi.
    PowerShell sudah memiliki string / di sini-string dengan tanda kutip tunggal dan ganda.
    Tujuan kami adalah untuk memahami bagaimana menerapkan / memperbaiki / meningkatkannya.
  2. Pengguna ingin menjalankan file yang dapat dieksekusi atau shell

    • sembarang yang dapat dieksekusi - perintah dimulai dengan nama aplikasi dan mengikuti argumen

      • dengan / tanpa interpolasi

      • dalam satu baris / multi baris

    • shell mungkin merupakan kasus khusus karena argumennya adalah _script_

      • dalam skenario salin-tempel, pengguna tidak ingin interpolasi dan ingin satu baris dan banyak baris

      • dalam skenario skrip, pengguna ingin mengaktifkan / menonaktifkan interpolasi dan menginginkan satu baris dan banyak baris

    Pikiran:
    Ini membuat kami berpikir bahwa perilaku skenario salin-tempel harus default.
    Terminator baris bergantung pada executable (di bash, `di PowerShell). Ini membuat kami berpikir bahwa:
    (1) shell harus secara eksplisit dinyatakan sebagai yang dapat dieksekusi,
    (2) mungkin dapat dieksekusi dengan multi baris harus dipanggil melalui shell atau kita harus melakukan parsing khusus (untuk menghapus terminator dan membangun daftar argumen kembali ke masalah dengan melarikan diri)
    (3) kita bisa mengatasi skenario copy-paste di PSReadline. Itu bisa mengubah buffer ke perintah PowerShell kanan.

  3. Pengguna menginginkan single line dan multiline.

    • mungkin kita perlu meningkatkan string di sini untuk satu baris guna menangani beberapa skenario seperti yang dibahas sebelumnya.
    • lihat 2 - (2) - selalu gunakan shell untuk multiline atau terapkan parsing khusus

Saya tidak ingin menulis lebih banyak karena @TSlivede dan @ mklement0 dapat memperbarui pemikiran dan kesimpulan mereka dari sebelumnya, tetapi sekarang dapat didasarkan pada penerimaan perubahan yang melanggar. Saya akan meminta untuk membuka masalah baru (dan menutup semua yang lama), menghitung semua kasus penggunaan (dimulai dengan @ @ rkeithhill 's dan menambahkan lebih banyak), dan mungkin membuat pengujian Pester - ini akan menjadi langkah yang bagus untuk memperbaiki Masalah tersebut.

Saya hanya ingin menambahkan bahwa kami dapat mempertimbangkan cmdlet baru untuk menyederhanakan adopsi pengguna seperti Invoke-Shell (Invoke-NativeShell), Test-Arguments (seperti echoargs.exe untuk menunjukkan bahwa aplikasi asli mendapat dan menunjukkan bantuan untuk pengguna), Convert-Arguments ( untuk mengonversi masukan pengguna ke argumen lolos kanan).

PS: Seperti yang saya tunjukkan di atas, perilaku baris tunggal dapat dengan mudah memilih keluar untuk kompatibilitas mundur pada waktu proses.

Terminator baris bergantung pada executable (di bash, `di PowerShell).

\ bukan terminator baris di bash .

Penyebab interpolasi tidak bekerja. Sebab itu bukan proposal final - ini mendemonstrasikan bagaimana kami dapat menerapkan perbaikan dalam hitungan menit. Dan terutama demo bahwa kita tidak memerlukan operator panggilan asli sama sekali seperti yang ditunjukkan @ mklement0 juga.

Dengan cara yang sama kami dapat memperbaiki semua bug dalam beberapa menit jika kami baru saja menghapus repo. Itu istirahat yang cukup besar yang Anda usulkan. Sekalipun hanya hipotesis saya tidak melihat bagaimana itu membantu.

Sekalipun hanya hipotesis saya tidak melihat bagaimana itu membantu.

@SeeminglyScience Sepertinya kita berada dalam konteks yang berbeda. Saya mengatakan bahwa kita dapat menerapkan perbaikan untuk panggilan asli satu baris sebagai perubahan yang melanggar tetapi tanpa merusak Parser. Dengan kata lain, kita bahkan dapat mengubah perilaku dengan cepat, tidak peduli perilaku baru apa yang akan kita terapkan.

Dengan kata lain, kita bahkan dapat mengubah perilaku dengan cepat, tidak peduli perilaku baru apa yang akan kita terapkan.

Saya kira hal yang saya lewatkan adalah bagaimana Anda mengubah perilaku itu dengan cepat tanpa secara eksplisit memintanya (seperti dengan panggilan operator asli).

@tokopedia

_Jika kita (dan PowerShell) tahu bahwa kita menjalankan executable asli, mengapa kita perlu "memanggil operator asli" sama sekali? _

Jika PowerShell mengurai string input dan mendapatkan CommandAst, maka PowerShell akan menemukan perintah tersebut.
Jika perintah adalah perintah asli, PowerShell mengonversi ast ke NativeCommandProcessor.
Kita dapat mengimplementasikan baru (eksperimental NativeCommandProcessor) untuk kasus yang akan mengurai ulang tingkat Ast (itu adalah string input) sehingga untuk mendapatkan nama / jalur yang dapat dieksekusi asli dan sisa string sebagai argumen atau argumen oleh aturan OS.

Jika pengguna ingin menyalin-tempel dari shell, dia harus mengetik "cmd" atau "bash" - yang akan berfungsi tanpa mengedit.
Jika pengguna ingin menyalin-tempel baris perintah asli akan berfungsi juga seperti g++ timer.cpp @conanbuildinfo.args -o timer --std=c++11 .

Saya ingin mengkonfirmasi apa yang Anda maksud dengan itu: Apakah Anda pada dasarnya menyarankan untuk mengabaikan semua sintaks PowerShell, saat memanggil executable eksternal?

Khususnya: Apakah Anda menyarankan, yang berjalan misalnya

/bin/echo (1..5)

di PowerShell tidak akan lagi mengeluarkan 1 2 3 4 5 tetapi harus mengeluarkan literal (1..5) ?

Jika itu benar-benar yang Anda sarankan, maka saya harus mengatakan: Saya pikir itu ide yang buruk.

Itu tidak menyederhanakan banyak hal (executable eksternal berperilaku sekarang secara sintaksis berbeda dari cmdlet internal) dan juga tidak perlu melakukan apa pun dengan # 1995 IMHO ...

@bayu_joo
Dari atas :

  • Akankah shell lain atau bahasa lain menerapkan ini atau sudahkah mereka? Di tingkat sintaks, atau di tingkat lain? Jika ya, bagaimana caranya?

Satu-satunya hal yang terlintas di benak saya adalah operator ipythons ! :

Menjalankan !ps -'fax' || true dalam keluaran ipython:

  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 tidak menampilkan tanda kutip di sekitar argumen , tetapi ps -'fax' || true benar-benar diberikan sebagai satu argumen tunggal untuk bash.)

Namun, fitur ini masih memungkinkan interpolasi variabel python ke dalam perintah itu ( {pyvar} ).

Dan mirip dengan @ mklement0 's contoh , ipython hanya alat ini

karena itu sendiri bukan cangkang

Jika ipython hanya mengizinkan sintaks python, itu tidak akan berguna sebagai shell, jadi mereka mengizinkan sintaks ini untuk meneruskan perintah ke bash agar dapat digunakan sebagai shell. Powershell di sisi lain mengklaim sebagai shell (sampai # 1995 diselesaikan, saya tidak akan mengatakan bahwa itu adalah shell), jadi akan sangat aneh untuk menambahkan sintaks khusus untuk memanggil shell lain .

Jika sesuatu seperti ini mendapatkan alasan apa pun yang benar-benar diterapkan (mudah-mudahan tidak), saya sarankan untuk menggunakan ! daripada --% sebagai "operator shell panggilan".

! adalah sesuatu yang mungkin ditebak orang (karena mereka tahu ! untuk tujuan itu dari ipython (atau dari mode perintah vim atau dari less atau dari ftp ) )

--% di sisi lain lebih sulit untuk diketik, tidak mungkin ditebak dan yang paling penting: Penggunaan --% menurut pendapat saya sangat sedikit kesamaannya dengan "berikan barang ke shell lain" tingkah laku. --% mengemulasi tepat satu elemen sintaks cmd: substitusi variabel (dan bahkan itu tidak sepenuhnya). Itu tidak mendukung escape char ^ , tidak mengizinkan pengalihan ke file, dan seterusnya. Satu-satunya hal yang agak berguna tentang --% ini adalah kemampuan untuk meneruskan konten kata demi kata ke dalam lpCommandLine - tetapi itu adalah sesuatu yang "operator shell panggilan" yang diusulkan tidak pandai.

Satu lagi perbedaan (yang telah disebutkan) antara "operator shell panggilan" yang diusulkan dan --% : Yang satu berakhir di pipa, yang lain tidak - sangat membingungkan bagi pengguna baru. ! di sisi lain meneruskan | ke shell di semua aplikasi yang saya uji sejauh ini (ipython, vim, less, ed, dll.).

HELP about_Logical_Operators -S

Ya, ! dengan sendirinya bermasalah karena ini adalah operator negasi logis dalam bahasa tersebut.

BTW salah satu proposal alternatif adalah &! - semacam operator "call native / shell".

Saya berharap @TSlivede lebih menekankan bagian "semoga tidak" lebih banyak ketika dia mengatakan "Jika sesuatu seperti ini benar-benar diterapkan karena alasan apa pun (semoga tidak)"

  • Tidak ada operator / pernyataan _dengan argumen individual_ yang dapat menyelesaikan masalah I-want-to-use-PowerShell-values-in-the-native-native-command-line dengan rapi, mengingat bahwa $ digunakan sebagai variabel sigil di _both_ PowerShell dan cangkang mirip POSIX.

  • Tidak ada operator / pernyataan _tanpa pembatas eksplisit di sekitar seluruh baris perintah asli_ yang dapat menyelesaikan masalah di mana-apakah-the-native-command-line-end (yang mungkin Anda pedulikan atau tidak pedulikan).

@ PowerShell / PowerShell-committee membahas hal ini hari ini. Pada titik ini, tampaknya tidak ada kesepakatan tentang pernyataan masalah awal atau desain tentang cara menyelesaikannya sehingga kami tidak yakin kami bisa memasukkannya ke dalam 7.1 dengan desain yang stabil.

@ PowerShell / PowerShell-committee membahas hal ini hari ini. Pada titik ini, tampaknya tidak ada kesepakatan tentang pernyataan masalah awal atau desain tentang cara menyelesaikannya sehingga kami tidak yakin kami bisa memasukkannya ke dalam 7.1 dengan desain yang stabil.

182 komentar!

Ada beberapa diskusi bagus tentang ini! Saya akan terus memantau setiap komentar baru tentang masalah ini. Kami masih mendorong komunitas untuk mengimplementasikan cmdlet Invoke-NativeCommand type yang dipublikasikan ke PSGallery terlepas dari masalah ini.

Saya pikir sangat disayangkan, ketika Anda memiliki solusi kompromi tetapi sangat berguna di https://github.com/PowerShell/PowerShell/issues/13068#issuecomment -662732627, untuk menghentikan ini. Saya tahu Anda menginginkan konsensus, tetapi terkadang kompromi adalah yang terbaik yang bisa terjadi. Tidak, ini tidak sempurna, tetapi solusi SO satu baris akan sangat berguna. Setidaknya menurut pendapat satu orang ini.

@essentialexch agar jelas, kami bahkan tidak memiliki konsensus dalam tim PowerShell

Karena ini ditunda bagaimana dengan pelaksanaan pembantu

kita dapat mempertimbangkan cmdlet baru untuk menyederhanakan adopsi pengguna seperti Invoke-Shell (Invoke-NativeShell), Test-Arguments (seperti echoargs.exe untuk menunjukkan bahwa aplikasi asli mendapat dan menunjukkan bantuan bagi pengguna), Convert-Arguments (untuk mengonversi masukan pengguna ke argumen lolos kanan).

Saya pikir Test-Arguments bisa sangat berguna.

Saya baru saja menerbitkan sebuah modul, Native , ( Install-Module Native -Scope CurrentUser ) yang saya undang untuk Anda semua untuk mencoba dan perintah siapa yang akan saya gunakan di bawah ; kasus penggunaan numerik yang direferensikan berasal dari komentar @rkeithhill di atas .

Jika kita ingin kabut konseptual menjadi jelas, saya pikir kita perlu membingkai kasus penggunaan secara berbeda.
_Tidak satupun dari mereka memerlukan perubahan apa pun dalam parsing_.

Kasus penggunaan [native-shell call]:

Anda ingin menjalankan perintah _individual_ (use case 1) atau seluruh _multi-command command line_ (use case 2) _written untuk platform-native shell_ (masalah ini):

  • Karena Anda menggunakan sintaks shell yang berbeda, Anda meneruskan perintah (baris) _sebagai satu string_ ke shell target, agar _it_ melakukan parsing; Interpolasi string PowerShell menawarkan kemampuan untuk menyematkan nilai PowerShell ke dalam string yang diteruskan (kasus penggunaan 2a).
  • ins ( Invoke-NativeShell ) mencakup kasus penggunaan ini.
# 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'

Sintaksis string di sini bukanlah yang paling nyaman (karena itu saran untuk mengimplementasikan varian sebaris - lihat # 13204), tetapi Anda tidak _have_ untuk menggunakannya; untuk perintah verbatim, Anda dapat menggunakan '...' , yang hanya membutuhkan _doubling_ tertanam ' , jika ada.

Selain itu, berikut ini pengganti yang wajar untuk "operator StackOverflow" :

Jika Anda menempatkan berikut PSReadLine handler kunci dalam Anda $PROFILE berkas, Anda akan dapat menggunakan Alt-v untuk perancah panggilan ke ins dengan kata demi kata di sini-string tempat teks papan klip saat ini ditempel.Masukkan mengirimkan panggilan.

# 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))
}

Kasus penggunaan [panggilan langsung yang dapat dijalankan]:

Anda ingin memanggil _single external executable_ menggunakan sintaks _PowerShell_, dengan _individual arguments_ (gunakan kasus 1a dan 3).

  • Ini adalah mandat inti dari shell apa pun, dan sangat penting agar shell berfungsi dengan baik.

    • Anda harus dapat mengandalkan PowerShell untuk dapat melewati argumen apa pun yang dihasilkan dari _its_ parsing _as-is_ ke target yang dapat dieksekusi. Saat ini bukan masalahnya - lihat # 1995 .
  • Ini mengharuskan Anda untuk memahami sintaks _PowerShell_ dan metakarakter mode argumen _its_.

    • Anda harus menyadari bahwa ` digunakan sebagai karakter escape dan untuk kelanjutan baris.
    • Anda perlu menyadari bahwa PowerShell memiliki karakter meta tambahan yang memerlukan kutipan / pelolosan untuk penggunaan verbatim; ini adalah (perhatikan bahwa @ hanya bermasalah sebagai karakter pertama argumen.):

      • untuk kerangka seperti POSIX (misalnya, Bash): @ { } ` (dan $ , jika Anda ingin mencegah ekspansi di muka oleh PowerShell)
      • untuk cmd.exe : ( ) @ { } # `
      • Satu ` satu printf %s `@list.txt ).

Sementara kita menunggu # 1995 diperbaiki, fungsi ie (untuk i nvoke (eksternal) e xecutable) mengisi celah tersebut, cukup dengan melakukan prapengiriman ke panggilan langsung; misalnya, alih-alih panggilan berikut:

# 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" }'

Anda akan menggunakan yang berikut ini:

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

Modul Native hadir dengan sesuatu yang mirip dengan echoArgs.exe , perintah dbea ( Debug-ExecutableArguments ); contoh keluaran di 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"

Dengan menggunakan sakelar -UseIe ( -ie ), Anda dapat memberi tahu dbea untuk meneruskan argumen melalui ie , yang menunjukkan bahwa ini memperbaiki masalah:

# 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"

Catatan: Setelah # 1995 diperbaiki, ie tidak lagi diperlukan; untuk kepentingan kompatibilitas ke depan, ie dirancang untuk mendeteksi dan secara otomatis menunda perbaikan; yaitu, setelah perbaikan dilakukan, ie akan berhenti menerapkan penyelesaiannya dan akan secara efektif bertindak seperti panggilan langsung / & .

Kasus penggunaan [panggilan eksekusi Windows nakal langsung]:

Ada dua masalah utama, yang muncul di _Windows only_:

  • Anda menggunakan executable "nakal" yang memiliki persyaratan kutipan yang berbeda dari konvensi yang paling banyak digunakan ; misal, msiexec.exe dan msdeploy.exe memerlukan prop="<value with spaces>" untuk dikutip dengan cara yang tepat - kutipan hanya di sekitar bagian _value_ - meskipun "prop=<value with spaces>" - mengutip dari keseluruhan argumen - _should_ setara (yang terakhir adalah apa yang PowerShell - dapat dibenarkan - lakukan di belakang layar).

  • Anda memanggil _a file batch_ dengan _an argumen yang tidak berisi spasi, tetapi berisi cmd.exe metacharacters_ seperti & , ^ , atau | ; misalnya:

    • .\someBatchFile.cmd 'http://example.org/a&b'
    • PowerShell - justifiably - melewati http://example.org/a&b _unquoted_ (karena tidak ada spasi yang disematkan), tetapi ini merusak pemanggilan file batch, karena cmd.exe - tidak masuk akal - subjek argumen yang diteruskan ke file batch ke aturan penguraian yang sama yang akan diterapkan di dalam cmd.exe daripada menerimanya sebagai literal.

    • Catatan: Meskipun menggunakan file batch untuk _directly_ mengimplementasikan fungsionalitas mungkin berkurang, menggunakannya sebagai titik masuk _CLI_ masih sangat umum, seperti Azure az CLI, yang diimplementasikan sebagai file batch az.cmd .

Catatan: ie secara otomatis menangani skenario ini untuk file batch dan untuk msiexec.exe dan msdeploy.exe , jadi untuk panggilan _most_ tidak diperlukan upaya ekstra ; bagaimanapun, tidak mungkin untuk mengantisipasi _all_ executable "nakal".

Ada dua cara untuk mengatasinya:

  • Mengingat bahwa cmd.exe , setelah menerapkan interpretasinya sendiri ke argumen pada baris perintah, _does_ mempertahankan kutipan seperti yang ditentukan, Anda dapat mendelegasikan ke panggilan ins di Windows:

    • ins '.\someBatchFile.cmd "http://example.org/a&b"'
    • Jika Anda menggunakan string _expandable_, ini memungkinkan Anda untuk menyematkan nilai PowerShell ke dalam string perintah.

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

  • Alternatifnya, gunakan implementasi --% , tetapi waspadalah terhadap batasannya:

    • .\someBatchFile.cmd --% "http://example.org/a&b"'
    • Mengingat bagaimana --% diimplementasikan, satu-satunya cara untuk menanamkan nilai PowerShell adalah - dengan canggung - mendefinisikan _aux. variabel lingkungan_ dan referensikan dengan sintaks %...% :

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


Penanganan kesalahan

Https://github.com/PowerShell/PowerShell-RFC/pull/88 yang tertunda akan membawa integrasi penanganan kesalahan yang lebih baik dengan executable eksternal (asli).

Sementara itu, modul Native dikirimkan dengan dua fitur ad-hoc opt-in untuk memperlakukan kode keluar bukan nol sebagai kesalahan penghentian skrip :

  • ins mendukung saklar -e / -ErrorOnFailure , yang akan memunculkan kesalahan jika $LASTEXITCODE bukan nol setelah panggilan ke shell asli.

  • iee adalah fungsi pembungkus untuk ie yang secara analogis memunculkan kesalahan jika $LASTEXITCODE bukan nol setelah panggilan ke eksekusi eksternal.

Ada banyak seluk-beluk perintah yang dikirimkan bersama modul.
Bantuan berbasis komentar yang cukup luas semoga cukup mencakupnya.

Jika kita ingin kabut konseptual menjadi jelas, saya pikir kita perlu membingkai kasus penggunaan secara berbeda.

Bagus! Apa yang saya posting sebelumnya hanya untuk membuat orang berpikir tentang membuat kasus penggunaan yang lebih banyak dan lebih baik.

Saya harus menjelaskan beberapa aspek penting dari ins ( Invoke-NativeShell ) yang berbeda dari yang saya usulkan sebelumnya; tujuannya adalah untuk memperhitungkan keberadaan bash di mana-mana dan untuk menyediakan CLI yang konsisten di seluruh platform.

  • Di Unix , saya memutuskan untuk menelepon /bin/bash daripada /bin/sh , mengingat keberadaan Bash di mana-mana, tetapi Anda dapat memilih untuk menggunakan /bin/sh dengan -UseSh ( -sh ) ( /bin/sh juga berfungsi sebagai fallback jika /bin/bash tidak ada).

    • Untuk mendapatkan pengalaman yang konsisten di seluruh formulir dan platform permintaan, saya menyembunyikan kemampuan untuk menyetel $0 , nama permintaan; yaitu, argumen pass-through apa pun yang dimulai dengan $1 , yang konsisten dengan bagaimana argumen diteruskan saat Anda menyalurkan skrip dari pipeline, dan kemungkinan yang diharapkan pengguna:
# 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
  • Di Windows, saya harus menggunakan file _batch_ sementara di belakang layar karena alasan teknis, tetapi menurut saya penggunaan sintaks file batch pada akhirnya adalah pilihan yang lebih baik ( %%i daripada %i di for variabel loop, kemampuan untuk keluar dari % sebagai %% ).

    • Penggunaan file batch juga memungkinkan dukungan untuk argumen pass-through, seperti pada 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]
Apakah halaman ini membantu?
0 / 5 - 0 peringkat