POSIX ve Windows üzerinde çalışan yürütülebilir bir komut dosyası


16

Zorluk : Windows'a özgü rasgele kod yürütmek foo.cmdiçin vanilya Windows cmd.exeisteminden (yönetici modunda değil PowerShell değil) çağrılabilen tek bir komut dosyası yazın ...

> .\foo.cmd
Hello Windows! 

... ama aynı zamanda kabuk tipik bir POSIX uyumlu (Linux / OSX) dan değiştirilmeden çağrılabilir istemi ( bash, tcshveya zsh), keyfi POSIX özel kodu çalıştırmak için:

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

... üçüncü taraf tercümanların / araçların kurulumunu veya oluşturulmasını gerektirmeden.

Bunun mümkün olduğunu biliyorum, ancak cruft (yani Windows'da, bir veya iki satır çöp / hata mesajı "Merhaba Windows!" Dan önce stderr veya stdout'a yazdırılır).

Kazanan kriter (ilk olarak) ham çizgi sayısının ve (ikinci) ham karakter sayısının en aza indirilmesidir.

Cruft, (keyfi) yük koduyla üretilmeyen herhangi bir konsol çıkışı (stdout veya stderr) olarak tanımlanabilir. Boş satırlar satır sayımında sayılır. Yeni satırlar karakter sayımında sayılmaz. Cruft skorları her iki platformda da toplanmalıdır. Bunun gibi mekanizmaları göz ardı edelim cls, ancak önceki terminal çıktısını köreltme pahasına. Windows @echo offhenüz dönmediğiniz için komutlarınızı yansıtıyorsa , geçerli dizini ve istemi yazdırırken harcadığı karakterleri hariç tutalım.

İkincil bir kriter, içindeki çözümün basitliği / şıklığıdır foo.cmd: "altyapı", keyfi yük kodunda doğrudan yer almayan herhangi bir karakter olarak tanımlanırsa, önce altyapı karakterlerini içeren satır sayısını ve ikinci olarak da toplam altyapı sayısını en aza indirin karakter.

POSIX kısmı CRLF satır sonlarına sahip dosyaya rağmen çalışacaksa ekstra kudos! (Son bölümün bile mümkün olduğundan emin değilim.)

Başkalarının bir şansı olduğunda buraya göndereceğim mevcut çözümüm 6 satırlık altyapı kodu kullanıyor (yeni satırlar hariç 52 karakter). İkisi boş olan ve tümü Windows'ta gerçekleşen 5 satır ham üretiyor (yeni satırlar hariç ve bu satırlardan ikisinde görünen geçerli dizin / bilgi istemi dizesi hariç 30 karakter).


vardır ya, bir kabuk / toplu komut olunur?
kedi

1
DOS için çevrimiçi bir deneme ortamı bilen var mı?
Dijital Travma

1
Bulduğum bu bir ama bana girmesine izin vermez ":", "\", "{" veya "}" karakterleri: - /
Dijital Travma

@DigitalTrauma Şarap var (eğer kuruyorsanız, kurmanız gerekirdi, çünkü kullanışlı)
kedi

1
@cat teşekkürler - Cevabım şuan şarap altında çalışıyor gibi görünüyor.
Dijital Travma

Yanıtlar:


15

0 ham hat, 0 ham karakter, 2 infra. çizgileri, 21 infra. karakter, CRLF tamam

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

Diğer çözüm kaldırıldı.

exit /bDigital Trauma'nın cevabından 17 karakter kullanılıyor :

:<<@exit/b
@echo Hello Windows!
@exit/b
echo "Hello POSIX!" #

Güçlü rakip! Özellikle ikinci versiyon (basitlik / zarafet kriterinde, yük hatlarını ilk versiyonun yaptığı gibi karıştırmak zorunda değilsiniz). Bu benim için Windows ve OSX'de çalışıyor. Başlangıçta : command not found, boş bir satırın posix yüküne :süründüğü zaman bir satır sarım aldım, ama sonunda bunun ilk satırda değil, korumasız CRLF'ler yüzünden olduğunu anladım #. Bir #!satırın gerekli olmadığı benim için bir haberdi - bu, önceki sürümümde Windows cruft satırlarından ikisinden sorumluydu.
jez

İlk sürümü skor-beri de bunu tahminen karakterleri ekler zor : ` >&3` \ için her yük hattı, sana onun altyapı maliyeti keyfi yüksek olduğunu söyleyebiliriz sanırım.
jez

@jez Cevaplar için sayısal bir puan mı hesaplıyorsunuz? Eğer öyleyse, bunun nasıl yapılacağı sorusunda daha açık hale getirmeniz gerekir.
Dijital Travma

Ben codegolf için yeniyim, bu yüzden TBH cevapları bir şekilde objektif olarak almamın beklendiğini düşündüm . Yine de sorunun açıklığa kavuşturduğunu düşünüyorum: ilk olarak, sınır çizgilerinin sayısı; bunun üzerine akılsız karakter sayısı ile bağları koparmak; daha sonra altyapı satırı sayısı, ardından altyapı karakter sayısı. Jimmy'nin ilk çözümü gibi faydalı yük hatlarını kapatan çözümler beklemiyordum. Soruyu istenmeyen bir şekilde açıklığa kavuşturmak için biraz değiştireceğim (bu hafif goalpost kayması için özür dilerim, ancak ikinci çözümünü veya şimdiye kadarki herhangi bir sürümünü etkilediğini sanmıyorum)
jez

Görünüşe göre cevaplarımız birbirine yaklaşıyor ;-) Heredoc kullanımı ile olsa puanlama avantajı var. Final #gerekli mi?
Dijital Travma

4

Skor 0 cruft + 4 infra hattı + 32 infra char. LF ve CRLF TAMAM.

Bu, bu blogda bulduğum şeylere dayanıyor , Amiga bitleri ve diğer gereksiz çizgiler çıkarıldı. DOS satırları \satır devam etmek yerine yorum tırnak içine sakladı , böylece bu hem CRLF hem de LF ile çalışabilir.

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

DOS CRLF veya * nix LF satır sonlarıyla Ubuntu, OSX ve şarapta çalışır:

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:~$ 

Bunu tam olarak (CRLF'lerle) bir * nix makinesinde (OSX dahil) oluşturmak için aşağıdakileri bir terminale yapıştırın:

[ $(uname) = Darwin ] && decode=-D || decode=-d
ubuntu@ubuntu:~$ base64 $decode > dosix.bat << EOF
QFJFTSAoKSg6KSAjDQpAUkVNICINCkBFQ0hPIEhlbGxvIFdpbmRvd3MhDQpARVhJVCAvQg0KQFJF
TSAiDQplY2hvIEhlbGxvIFBPU0lYIQ0K
EOF

Güzel gözüküyor! dosixçok güzel bir isim. Ancak Mac'imde (OS 10.9.4, Darwin Kernel Sürüm 13.3.0, GNU bash sürüm 3.2.51) ile çalışmaz: ./dosix.cmd: line 13: syntax error: unexpected end of file Neden herhangi bir fikir?
jez

@jez, UTF-8 ile kodlanmış dosyayı kaydettiğinizden ve Windows satır sonlarını koruduğunuzdan emin olun!
kedi

Ah, çünkü Windows satır sonlarını bilmiyordum ve ilk sürümü kullanıyordum.
jez

Bash'e CR karakterini insert (veya Cv) girerek girebileceğinizi (veya Cm) unutmayın.
jimmy23013

@jez Yani bu 0 cruft hatları + 4 altyapı hattı + 32 altyapı grafiği olarak puanlar. Karşılaştırma için tek bir puan oluşturmak üzere bu sayılar anlamlı bir şekilde birleştirilmeli mi?
Dijital Travma

2

Zaten dövüldüğünden beri kullandığım çözümü zaten göndereceğim. Aynı blog girişini okumuş olması gerektiğini düşündüğüm bir meslektaşımın izniyleDigital Trauma ile .

#!/bin/sh # >NUL 2>&1
echo \
@goto c \
>/dev/null
echo "Hello Posix!"
exit
:c
@echo Hello Windows!
  • Windows cruft: 5 satır (ikisi boş) / 30 karakter
  • OSX sarfiyatı: 0
  • Altyapı: 6 satır / 52 karakter
  • CRLF uyumluluğu: yalnızca hatta adlandırılan yorumlayıcı #!umursamıyorsa (bu yüzden shve benzeri standart tercümanlar için başarısız olur)

POSIX'te bir komut dosyası her zaman ile başlar #!, yani POSIX sisteminde geçerli bir komut dosyası olmak için tek yanıt sizindir. Tabii diğerlerinden bazıları - ancak hatalı komut dosyaları için geçici çözüm içeren bir kabuktan başlatılırsa çalışabilir.
kasperd

Bunu bildiğim iyi oldu! POSIX uyumluluğu için katı kriterler konusunda bulanıkım. Benim asıl amacım, ne demek olursa olsun, en modern masaüstü sistemlerinde "kutudan çıkmış" olarak çalışan komut dosyalarına sahip olmaktır - Windows 7/8/10, Ubuntu, OSX ... Ne kadar evrensel komut dosyaları için geçici çözüm, Merak ediyorum? Her neyse, puanları kendime
vermeyeceğim

Hem cevap hem de sorunun aynı kişi tarafından yazıldığını fark etmemiştim. Çalıştığım tüm kabukların eksik bir #!çizgi için bir geçici çözümü olduğunu düşünüyorum , ancak senaryoyu yorumlamak için farklı kabuklar kullanacaklar. Bu, başlamayan bir "betik" #!in sadece bir kabukta değil, akla gelebilecek şekilde yorumlanabildiği her kabukta geçerli olması gerektiği anlamına gelir . Ama daha da kötüsü, sadece başka bir kabuktan başlatıldığında çalışır. Bu tür bir komut dosyası komut satırından çalışabilir, ancak sonunda kullanmayı düşündüğünüz bağlamda çalışmayabilir.
kasperd

Teşekkür ederim, bu çok eğitici şeyler ve tam da bu mücadeleyi başlatarak öğrenmeyi umduğum bir şey. Bunun önemli olacağı (veya olabileceği) durumlarda, #!düzenlenmiş cevabımdaki satır (21 karakterli 1 altyapı hattı), yalnızca Windows'un 2 satırlık ham maliyetiyle (biri boş) veya başkalarının cevabı ile birleştirilebilir veya 23 karakter.
jez

2

Yanıtların ve tartışmanın özeti / sentezi

Bu eğlenceliydi ve çok şey öğrendim.

POSIX sisteminizde komut dosyanızı bir #!satırla başlatmanız gerekiyorsa, Windows'a özgü bazı sarsıntılar kaçınılmazdır . Bunu yapmaktan başka seçeneğiniz yoksa, bu satır:

#!/bin/sh # 2>NUL

Muhtemelen alabileceği en iyisidir. Windows konsolunda bir boş satır ve bir satır ham çıktı çıkmasına neden olur. Ancak, olabilir a olmadan kurtulmak mümkün#! hattı: - bu bağlıdır, ancak çoğu sistemde, her zamanki kabuk yorumcularından biri scriptinizi sona erecek (sorun o olacak tercüman evrensel öngörülebilir değil olmasıdır komutla aynı olması gerekmez, komutu çağırmak için kullandığınız kabuk).

Bu zor ilk çizginin ötesinde, gerçekten dahice, acımasız çözümler vardı. Jimmy23013'ün kazanan sunumu sadece iki kısa altyapı hattından oluşuyordu ve :her iki platformda da "sessiz" bir çizgi uygulamak için karakterin ikili rolünü kullanıyordu ( facto no-op shve arkadaş olarak ve bir etiket olarak) işaretleyici cmd.exe):

:<<@exit/b

:: Arbitrary Windows code goes here

@exit/b
#
# Arbitrary POSIX code goes here 

İse bile CRLF satır sonları rağmen POSIX sistemlerinde böyle bir senaryo çalışmasını sağlamak için, ancak bir son vermeliyim çoğu tercümanlar için bunu yapmak mümkün her bir yorum veya açıklama karakteri ile POSIX bölümünün hattını (hatta boş satırlar).

Son olarak, herkesin girdisine dayanarak geliştirdiğim bir çözümün iki çeşidi. Neredeyse tüm dünyaların en iyisi olabilirler , çünkü eksiklikten kaynaklanan hasarı en aza indirir #!ve CRLF uyumluluğunu daha da pürüzsüz hale getirir. İki ekstra altyapı hattına ihtiyaç vardır. Öngörülemeyen POSIX kabuğu tarafından yalnızca bir (standartlaştırılmış) satır yorumlanmalıdır ve bu satır komut dosyasının geri kalanı için kabuğu seçmenize izin verir ( bashaşağıdaki örnekte):

:<<@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

Bu yorumlu çözümlerin güzelliğinin bir kısmı, hala CRLF-sağlam olmalarıdır: hattın sonuna<<:Z geldiği sürece , heredoc işlemci aslında jetonu arayacak ve bulacak:Z\r

Son bir bükülme olarak, bu sinir bozucu satır sonu yorumlarından kurtulabilir \rve satırları kabuğa geçirmeden önce karakterleri çıkararak CRLF sağlamlığını koruyabilirsiniz . Bu, öngörülemeyen kabuğa biraz daha fazla inanıyor ( { tr -d \\r|bash;}yerine kullanmak güzel olurdu , (tr -d \\r|bash)ancak kıvırcık parantezler sadece bash sözdizimidir):

:<<@GOTO:Z

@echo Hello Windows!

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

echo "Hello POSIX!"
ps

:Z

Tabii ki, bu yaklaşım stdin girdisini senaryoya aktarma yeteneğini feda eder.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.