GnuWin32 / sed perilaku tak terduga di Powershell

0

Saya menggunakan alat GnuWin32 pada Windows Command Line / Powershell .

Apa yang dilihat:

 11:15 enlil D:\Users\x> Get-ChildItem .gitconfig  | sed "s/ */ /g"


 D i r e c t o r y : D : \ U s e r s \ x


 M o d e L a s t W r i t e T i m e L e n g t h N a m e
 - - - - - - - - - - - - - - - - - - - - - - - - - - -
 - a - - - 6 / 2 3 / 2 0 1 4 4 : 1 1 P M 5 6 . g i t c o n f i g

Apa yang saya harapkan:

 11:15 enlil D:\Users\x> ls .gitconfig  | sed "s/ */ /g"


 Directory: D:\Users\x


 Mode LastWriteTime Length Name
 ---- ------------- ------ ----
 -a--- 6/23/2014 4:11 PM 56 .gitconfig

Tujuan saya adalah untuk menghilangkan ruang yang tidak perlu di antara kolom data, yang ditambahkan oleh PowerShell. Lucunya ini berfungsi dengan baik di satu komputer (dengan Win8.1), tetapi tidak bekerja di komputer lain dengan Win7.

Dan itu berfungsi untuk contoh yang lebih sederhana:

 11:49 enlil D:\Users\x> echo "t  a t" |  sed "s/ */ /g"
 t a t

Bantuan apa pun akan sangat dihargai.

FYI - Output normal Get-ChildItems terlihat seperti ini:

 11:22 enlil D:\Users\x> ls .gitconfig


    Directory: D:\Users\x


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         6/23/2014   4:11 PM         56 .gitconfig
mnmnc
sumber
Mengapa tidak menggunakan PowerShell saja untuk semuanya? Apa tujuan akhir?
EBGreen
Tujuan utamanya adalah untuk dapat menggunakan alat gnuWin32 seperti cutdan trdan sort. Ini cara yang saya sukai karena saya tidak terlalu menyukai sintaks Powershell Command | Select this and that | Format-table. Juga dalam powershell banyak hal yang dilewati pipa adalah benda-benda di mana di bash mereka adalah aliran - yang jauh lebih mudah untuk dimanipulasi untuk saya.
mnmnc
Ini akan menjadi masalah penyandian di lingkungan. Salah satu cara untuk menghindarinya adalah dengan menggunakan File-Out untuk menempatkan output ke dalam file dengan apa pun pengkodean bekerja kemudian membaca file kembali ke sed.
EBGreen

Jawaban:

2

Itu Unicode. Barang yang keluar dari sed adalah Unicode tanpa awalan 2-byte yang digunakan PowerShell untuk membedakan antara Unicode dan ASCII. Jadi PowerShell berpikir bahwa itu adalah ASCII dan membiarkan \ 0 byte (byte atas dari karakter Unicode 2-byte), yang ditampilkan sebagai kosong. Dan karena secara internal transaksi PowerShell di Unicode, itu sebenarnya memperluas setiap byte asli menjadi karakter Unicode 2-byte. Tidak ada cara untuk memaksa PowerShell agar menerima Unicode. Cara yang mungkin untuk mengatasinya adalah:

  1. Apakah Unicode datang sebagai input ke SED? Tidak mungkin tapi saya pikir mungkin. Periksa itu.

  2. Buat output SED mulai dengan indikator Unicode, \ uFEFF. Ini mungkin yang terlewatkan dalam kode sumber SED:

    _setmode(_fileno(stdout), _O_WTEXT); // probably present and makes it send Unicode
    wprintf(L"\uFEFF"); // probably missing
    

    Anda dapat menambahkan kode di dalam perintah SED, sesuatu seperti

    sed "1s/^/\xFF\xFE/;..." # won't work if SED produces Unicode but would work it SED passes Unicode through from its input
    sed "1s/^/\uFEFF/;..." # use if SED produces Unicode itself, hopefully SED supports \u
    
  3. Tulis output dari sed ke dalam file dan kemudian baca dengan Get-Content -Encoding Unicode. Perhatikan bahwa beralih ke file harus dilakukan dalam perintah di dalam cmd.exe, seperti:

    cmd /c "sed ... >file"
    

    Jika Anda hanya membiarkan file ditangani di PowerShell, file itu akan dikacaukan dengan cara yang sama.

  4. Jatuhkan \ 0 karakter dari teks yang dihasilkan di PowerShell. Ini tidak bekerja dengan baik dengan karakter internasional yang membuat byte Unicode yang berisi kode 0xA atau 0xD - Anda berakhir dengan pemisahan garis alih-alih mereka.

Sergey Babkin
sumber
Hebat, terima kasih banyak atas waktu dan analisisnya. Ini jauh lebih jelas bagi saya sekarang.
mnmnc