File skrip yang dapat dieksekusi yang berjalan pada POSIX dan Windows

16

Tantangan : menulis file skrip tunggal foo.cmdyang dapat dipanggil dari cmd.exeprompt vanilla Windows (bukan PowerShell, bukan dalam mode administrator), untuk mengeksekusi kode khusus Windows sewenang-wenang ...

> .\foo.cmd
Hello Windows! 

... tetapi juga akan dipanggil berubah dari khas POSIX-compliant (Linux / OSX) shell prompt ( bash, tcsh, atau zsh), untuk mengeksekusi sewenang-wenang kode POSIX-spesifik:

$ chmod a+x foo.cmd
$ ./foo.cmd
Hello POSIX!

... tanpa memerlukan instalasi atau pembuatan juru bahasa / alat pihak ketiga.

Saya tahu ini mungkin, tetapi dengan cruft (yaitu pada Windows, satu atau dua baris sampah / pesan kesalahan dicetak ke stderr atau stdout sebelum "Hello Windows!").

Kriteria yang menang adalah minimalisasi (pertama) jumlah baris cruft, dan (kedua) jumlah karakter cruft.

Cruft dapat didefinisikan sebagai output konsol (stdout atau stderr) yang tidak diproduksi oleh kode muatan (sewenang-wenang). Baris kosong dihitung dalam jumlah baris. Baris baru tidak dihitung dalam jumlah karakter. Skor Cruft harus dijumlahkan di kedua platform. Mari kita abaikan mekanisme seperti clsitu menyapu cruft tetapi dengan mengorbankan juga keluaran terminal sebelumnya. Jika Windows menggemakan perintah Anda karena Anda belum mengaktifkannya @echo off, mari kita kecualikan karakter yang dihabiskannya dalam mencetak direktori saat ini dan meminta.

Kriteria sekunder adalah kesederhanaan / keanggunan solusi di dalamnya foo.cmd: jika "infrastruktur" didefinisikan sebagai karakter apa pun yang tidak terlibat langsung dalam kode muatan sewenang-wenang, maka minimalkan terlebih dahulu jumlah baris yang berisi karakter infrastruktur, dan kedua jumlah total infrastruktur karakter.

Kudos ekstra jika bagian POSIX akan berfungsi meskipun file memiliki akhiran CRLF! (Tidak yakin bahwa bagian terakhir bahkan mungkin.)

Solusi saya yang ada, yang akan saya posting di sini setelah orang lain memiliki kesempatan, menggunakan 6 baris kode infrastruktur (52 karakter termasuk baris baru). Ini menghasilkan 5 baris cruft, dua di antaranya kosong, yang semuanya terjadi pada Windows (30 karakter tidak termasuk baris baru dan tidak termasuk direktori saat ini / string prompt yang muncul pada dua baris tersebut).

jez
sumber
harus menjadi skrip shell / batch, ya?
kucing
1
Adakah yang tahu tentang lingkungan try-it-online untuk DOS?
Trauma Digital
1
Saya menemukan yang satu ini tetapi tidak membiarkan saya memasukkan karakter ":", "\", "{" atau "}": - /
Digital Trauma
@DigitalTrauma Ada Wine (yang seharusnya Anda instal, jika tidak, karena praktis)
cat
1
@cat terima kasih - Jawaban saya tampaknya berfungsi di bawah anggur sekarang.
Trauma Digital

Jawaban:

15

0 baris cruft, 0 cruft chars, 2 infra. baris, 21 infra. karakter, CRLF ok

:<<@goto:eof
@echo Hello Windows!
@goto:eof
echo "Hello POSIX!" #

Menghapus solusi lain.

17 karakter menggunakan exit /bdari jawaban Digital Trauma:

:<<@exit/b
@echo Hello Windows!
@exit/b
echo "Hello POSIX!" #
jimmy23013
sumber
Pesaing yang kuat! Khususnya versi kedua (pada kriteria kesederhanaan / keanggunan, itu jauh lebih baik untuk tidak harus memotong garis payload seperti yang dilakukan versi pertama). Ini berjalan untuk saya di Windows dan OSX. Awalnya saya mendapat satu baris cruft mengatakan : command not foundsetiap kali baris kosong merayapi ke dalam posix payload, tetapi saya akhirnya menemukan bahwa itu bukan tentang :pada baris pertama melainkan karena CRLF yang tidak dilindungi oleh #. Bagi saya adalah berita bahwa sebuah #!baris tidak diperlukan — yang bertanggung jawab atas dua baris Windows cruft dalam versi saya sebelumnya.
1515
Versi pertama sulit untuk dinilai — karena mungkin menambahkan karakter : ` >&3` \ ke setiap baris payload, saya kira Anda bisa mengatakan biaya infrastrukturnya tinggi secara sewenang-wenang.
jez
@ Joez Anda menghitung skor numerik untuk jawaban? Jika demikian, Anda harus membuatnya lebih jelas dalam pertanyaan bagaimana melakukannya.
Trauma Digital
Saya baru mengenal codegolf, jadi TBH saya pikir saya diharapkan untuk mencetak jawaban secara objektif. Meskipun demikian saya pikir pertanyaannya memperjelas: pertama, jumlah garis kasar; memutus ikatan itu dengan jumlah karakter cruft; kemudian pada jumlah garis infrastruktur, kemudian jumlah karakter infrastruktur. Saya tidak mengira solusi yang membuat garis payload, seperti solusi pertama jimmy. Saya akan sedikit mengubah pertanyaan untuk memperjelas bahwa itu tidak diinginkan (maaf untuk sedikit perubahan tiang gawang tapi saya tidak berpikir itu mempengaruhi solusi keduanya atau versi Anda sejauh ini)
jez
Sepertinya jawaban kami konvergen ;-) Anda memiliki keunggulan dalam penilaian meskipun dengan penggunaan heredoc. Apakah final itu #perlu?
Trauma Digital
4

Skor 0 cruft + 4 jalur infra + 32 infra karakter. LF & CRLF OKE.

Ini didasarkan pada apa yang saya temukan di blog ini , dengan bit Amiga dan garis yang tidak perlu lainnya dikeluarkan. Saya menyembunyikan baris DOS dalam tanda kutip komentar daripada menggunakan \baris berlanjut, sehingga ini dapat bekerja dengan CRLF dan LF.

@REM ()(:) #
@REM "
@ECHO Hello Windows!
@EXIT /B
@REM "
echo Hello POSIX!

Dengan ujung baris DOS CRLF atau * nix LF, ia bekerja di Ubuntu, OSX dan anggur:

ubuntu@ubuntu:~$ ./dosix.bat
Hello POSIX!
ubuntu@ubuntu:~$ wine cmd.exe
Wine CMD Version 5.1.2600 (1.6.2)

Z:\home\ubuntu>dosix.bat
Hello Windows!

Z:\home\ubuntu>exit
ubuntu@ubuntu:~$ 

Untuk membuat ini persis (dengan CRLF) pada mesin * nix (termasuk OSX), rekatkan yang berikut ini ke terminal:

[ $(uname) = Darwin ] && decode=-D || decode=-d
ubuntu@ubuntu:~$ base64 $decode > dosix.bat << EOF
QFJFTSAoKSg6KSAjDQpAUkVNICINCkBFQ0hPIEhlbGxvIFdpbmRvd3MhDQpARVhJVCAvQg0KQFJF
TSAiDQplY2hvIEhlbGxvIFBPU0lYIQ0K
EOF
digital Trauma
sumber
Terlihat bagus! dosixadalah nama yang bagus juga. Tetapi pada Mac saya (OS 10.9.4, Darwin Kernel Versi 13.3.0, GNU bash versi 3.2.51) gagal dijalankan dengan: ./dosix.cmd: line 13: syntax error: unexpected end of file Ada ide mengapa?
jez
@ jez pastikan Anda menyimpan file yang disandikan dengan UTF-8 dan menjaga ujung jalur Windows!
kucing
Ah, itu terjadi karena saya tidak sadar memiliki Windows line-endings dan menggunakan versi pertama.
jez
Perhatikan bahwa Anda dapat memasukkan karakter CR di Bash dengan memasukkan (atau Cv), masukkan (atau Cm).
jimmy23013
@ Joez Jadi ini skor sebagai 0 garis cruft + 4 jalur infrastruktur + 32 karakter infrastruktur. Haruskah angka-angka ini digabungkan dengan cara yang berarti untuk membuat skor tunggal untuk perbandingan?
Trauma Digital
2

Saya sudah memposting solusi yang telah saya gunakan, karena sudah dikalahkan. Ini milik seorang kolega saya yang saya pikir pasti telah membaca entri blog yang sama dengan Digital Trauma .

#!/bin/sh # >NUL 2>&1
echo \
@goto c \
>/dev/null
echo "Hello Posix!"
exit
:c
@echo Hello Windows!
  • Windows cruft: 5 baris (yang dua kosong) / 30 karakter
  • OSX cruft: 0
  • Infrastruktur: 6 baris / 52 karakter
  • Kompatibilitas CRLF: hanya jika penerjemah yang disebutkan di #!telepon tidak peduli (jadi untuk penerjemah standar seperti shdan teman-teman, gagal)
jez
sumber
Pada POSIX, skrip selalu dimulai dengan #! , yang berarti milik Anda adalah satu-satunya jawaban sejauh ini untuk menjadi skrip yang valid pada sistem POSIX. Tentu beberapa yang lain dapat dijalankan jika - tetapi hanya jika mereka dimulai dari shell dengan solusi untuk skrip yang salah.
kasperd
Senang mendengarnya! Saya kira saya tidak jelas tentang kriteria ketat untuk kepatuhan POSIX. Tujuan sebenarnya saya adalah memiliki file skrip yang berfungsi "di luar kotak" pada "sebagian besar" sistem desktop modern, apa pun artinya - Windows 7/8/10, Ubuntu, OSX ... Seberapa universal solusi untuk skrip shebangless, Aku penasaran? Ngomong-ngomong, aku tidak akan memberikan poin untuk diriku sendiri :-)
jez
Saya tidak memperhatikan bahwa jawaban dan pertanyaan ditulis oleh orang yang sama. Saya pikir semua shell yang telah bekerja dengan saya memiliki solusi untuk #!garis yang hilang , tetapi mereka akan menggunakan shell yang berbeda untuk menafsirkan skrip. Itu berarti "skrip" yang tidak dimulai dengan #!harus valid tidak hanya dalam satu shell, tetapi setiap shell yang masuk akal dapat ditafsirkan oleh. Tetapi yang lebih buruk, itu hanya bekerja ketika dimulai dari shell lain. Skrip seperti itu mungkin berfungsi dari baris perintah, tetapi tidak dalam konteks di mana Anda akhirnya bermaksud menggunakannya.
kasperd
Terima kasih, ini adalah hal yang sangat mendidik dan persis seperti yang saya harapkan untuk dipelajari dengan memulai tantangan ini. Untuk kasus-kasus di mana ini akan (atau mungkin) penting, #!baris dalam jawaban saya yang diedit (1 garis infrastruktur dengan 21 karakter) dapat digabungkan dengan jawaban orang lain dengan biaya Windows hanya 2 baris (yang satu kosong) atau 23 karakter.
jez
2

Ringkasan / sintesis jawaban dan diskusi

Ini menyenangkan, dan saya belajar banyak.

Beberapa pengerjaan khusus Windows tidak dapat dihindari jika, pada sistem POSIX Anda, Anda perlu memulai skrip Anda dengan sebuah #!baris. Jika Anda tidak memiliki alternatif selain melakukan ini, maka baris ini:

#!/bin/sh # 2>NUL

mungkin yang terbaik yang bisa didapat. Ini menyebabkan satu baris kosong dan satu baris cruft menjadi output pada konsol Windows. Namun, Anda mungkin dapat pergi tanpa #!garis: pada sebagian besar sistem, salah satu penerjemah shell yang biasa akan menjalankan skrip (masalahnya adalah tidak dapat diprediksi secara universal penafsir mana yang akan - tergantung pada, tetapi akan tidak harus identik dengan, shell yang Anda gunakan untuk menjalankan perintah).

Di luar garis pertama yang rumit itu, ada beberapa solusi tanpa ampun yang benar-benar cerdik. Pengajuan pemenang oleh jimmy23013 hanya terdiri dari dua jalur infrastruktur pendek, dan memanfaatkan peran ganda :karakter untuk menerapkan garis "sunyi" pada kedua platform (sebagai no-op in -factosh dan teman-teman, dan sebagai label penanda di cmd.exe):

:<<@exit/b

:: Arbitrary Windows code goes here

@exit/b
#
# Arbitrary POSIX code goes here 

Hal ini dimungkinkan untuk membuat script seperti berjalan di sistem POSIX bahkan meskipun CRLF line-ujung, tetapi untuk melakukan hal ini untuk sebagian besar penafsir Anda harus mengakhiri setiap baris bagian POSIX Anda (bahkan baris kosong) dengan komentar atau komentar karakter.

Akhirnya, berikut adalah dua varian solusi yang saya kembangkan berdasarkan masukan semua orang. Mungkin saja hampir yang terbaik dari semua dunia, karena mereka meminimalkan kerusakan dari kurangnya #!dan membuat kompatibilitas CRLF lebih lancar. Dibutuhkan dua jalur infrastruktur tambahan. Hanya satu baris (standar) yang harus ditafsirkan oleh shell POSIX yang tidak dapat diprediksi, dan baris itu memungkinkan Anda untuk memilih shell untuk sisa skrip ( bashdalam contoh berikut):

:<<@GOTO:Z

@echo Hello Windows!

@GOTO:Z
bash "$@"<<:Z
#
echo "Hello POSIX!" #
ps # let's throw this into the payload to keep track of which shell is being used
#
:Z

Bagian dari keindahan dari solusi heredoc ini adalah bahwa mereka masih kuat-CRLF: selama <<:Zmuncul di akhir baris, prosesor heredoc sebenarnya akan mencari, dan akan menemukan, token:Z\r

Sebagai twist terakhir, Anda dapat menyingkirkan komentar end-of-line yang sial dan tetap mempertahankan kekokohan CRLF, dengan menghapus \r karakter sebelum meneruskannya ke shell. Ini menempatkan sedikit lebih banyak kepercayaan pada shell yang tidak dapat diprediksi (akan lebih baik untuk digunakan { tr -d \\r|bash;}sebagai ganti (tr -d \\r|bash)tapi kurung keriting adalah sintaks hanya-bash):

:<<@GOTO:Z

@echo Hello Windows!

@GOTO:Z
(tr -d \\r|bash "$@")<<:Z

echo "Hello POSIX!"
ps

:Z

Tentu saja, pendekatan ini mengorbankan kemampuan untuk menyalurkan input stdin ke dalam skrip.

jez
sumber