ไฟล์สคริปต์ที่สามารถเรียกทำงานได้ซึ่งทำงานบน POSIX และ Windows


16

ท้าทาย : เขียนไฟล์สคริปต์เดียวfoo.cmdซึ่งสามารถเรียกจากวานิลลาของ Windows cmd.exeพรอมต์ (ไม่ PowerShell ไม่ได้อยู่ในโหมดผู้ดูแลระบบ) ในการดำเนินการ Windows รหัสเฉพาะพล ...

> .\foo.cmd
Hello Windows! 

... แต่ยังถูกเรียกไม่เปลี่ยนแปลงจากปกติ POSIX สอดคล้อง (Linux / OSX) เปลือกพรอมต์ ( bash, tcshหรือzsh) ในการดำเนินการโดยพลการรหัส POSIX เฉพาะ:

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

... โดยไม่ต้องมีการติดตั้งหรือสร้างล่าม / เครื่องมือของบุคคลที่สาม

ฉันรู้ว่ามันเป็นไปได้ แต่ด้วย cruft (เช่นใน Windows บรรทัดข้อความขยะ / ข้อผิดพลาดหนึ่งหรือสองบรรทัดจะถูกพิมพ์ไปยัง stderr หรือ stdout ก่อน "Hello Windows!")

เกณฑ์ที่ชนะคือการลดจำนวนของบรรทัด cruft (แรก) และ (วินาที) จำนวนอักขระ cruft

Cruft สามารถกำหนดเป็นเอาท์พุทของคอนโซล (stdout หรือ stderr) ที่ไม่ได้ผลิตโดยรหัส payload (ตามอำเภอใจ) บรรทัดว่างจะถูกนับในการนับบรรทัด บรรทัดใหม่จะไม่ถูกนับในการนับตัวละคร คะแนน Cruft ควรจะถูกนำมารวมกันในทั้งสองแพลตฟอร์ม เรามองข้ามกลไกแบบนี้clsไปเพื่อกำจัด cruft แต่ก็ต้องทำการตัดเอาท์พุทของเทอร์มินัลก่อนหน้าด้วย หาก Windows สะท้อนคำสั่งของคุณเนื่องจากคุณยังไม่ได้เปิดใช้@echo offงานให้แยกอักขระที่ใช้ในการพิมพ์ไดเรกทอรีปัจจุบันและพรอมต์

เกณฑ์รองคือความเรียบง่าย / ความสง่างามของโซลูชันภายในfoo.cmd: ถ้า "โครงสร้างพื้นฐาน" ถูกกำหนดเป็นอักขระใด ๆ ที่ไม่เกี่ยวข้องโดยตรงในรหัส payload โดยพลการจากนั้นลดจำนวนบรรทัดที่มีอักขระโครงสร้างพื้นฐานเป็นอันดับแรกและลดจำนวนโครงสร้างพื้นฐานเป็นอันดับสอง ตัวละคร

ความรุ่งโรจน์เพิ่มเติมหากส่วน POSIX จะทำงานแม้จะมีไฟล์ที่มี CRLF line-endings! (ไม่แน่ใจว่าส่วนสุดท้ายเป็นไปได้หรือไม่)

โซลูชันที่มีอยู่ของฉันซึ่งฉันจะโพสต์ที่นี่เมื่อคนอื่นมีโอกาสใช้รหัสโครงสร้างพื้นฐาน 6 บรรทัด (52 ตัวอักษรยกเว้นบรรทัดใหม่) มันสร้าง cruft 5 บรรทัดโดยที่สองบรรทัดนั้นว่างเปล่าทั้งหมดนั้นเกิดขึ้นบน Windows (30 chars ยกเว้นการขึ้นบรรทัดใหม่และไม่รวมสตริงไดเรกทอรี / พรอมต์ปัจจุบันที่ปรากฏบนสองบรรทัดเหล่านั้น)


มีจะเป็นสคริปต์เชลล์ / ชุดยา?
แมว

1
ไม่มีใครรู้เกี่ยวกับสภาพแวดล้อมแบบลองใช้งานออนไลน์สำหรับ DOS หรือไม่
Digital Trauma

1
ฉันพบสิ่งนี้แต่ไม่อนุญาตให้ฉันป้อนอักขระ ":", "\", "{" หรือ "}": - /
Digital Trauma

@DigitalTrauma มีไวน์ (ซึ่งคุณควรจะติดตั้งถ้าคุณทำไม่ได้เพราะมันมีประโยชน์)
cat

1
@cat ขอบคุณ - คำตอบของฉันดูเหมือนจะทำงานภายใต้ไวน์ในขณะนี้
Digital Trauma

คำตอบ:


15

0 cruft lines, 0 cruft chars, 2 infra เส้น, 21 อินฟา ตัวอักษร CRLF ตกลง

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

ลบโซลูชันอื่น

17 ตัวอักษรที่ใช้exit /bจากคำตอบของ Digital Trauma:

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

คู่แข่งที่แข็งแกร่ง! โดยเฉพาะอย่างยิ่งรุ่นที่สอง (ในเกณฑ์ความเรียบง่าย / ความสง่างามมันยอดเยี่ยมกว่ามากที่ไม่จำเป็นต้องกำจัดสายการบรรจุในแบบที่รุ่นแรกทำ) สิ่งนี้ทำงานสำหรับฉันบน Windows และ OSX ตอนแรกผมมีหนึ่งบรรทัดของ cruft บอกว่า: command not foundเมื่อใดก็ตามที่พุ่งบรรทัดว่างลงในส่วนของข้อมูล POSIX แต่ในที่สุดผมก็คิดว่าไม่ได้เกี่ยวกับ:ในบรรทัดแรก แต่เพราะ CRLFs #ที่ไม่มีการป้องกันโดย มันเป็นข่าวสำหรับฉันว่า#!ไม่จำเป็นต้องมีบรรทัด - ซึ่งรับผิดชอบสองบรรทัดของ cruft ของ Windows ในเวอร์ชันก่อนหน้าของฉัน
jez

รุ่นแรกนั้นยากที่จะทำคะแนน - เนื่องจากมันจะเพิ่มตัวละคร: ` >&3` \ ลงในทุก ๆแถวของน้ำหนักบรรทุกฉันเดาว่าคุณอาจบอกได้ว่าต้นทุนโครงสร้างพื้นฐานนั้นสูงมากตามอำเภอใจ
jez

@jez คุณกำลังคำนวณคะแนนตัวเลขสำหรับคำตอบหรือไม่ ถ้าเป็นเช่นนั้นคุณต้องทำให้ชัดเจนยิ่งขึ้นในคำถามว่าต้องทำอย่างไร
Digital Trauma

ฉันใหม่ codegolf ดังนั้น TBH ฉันคิดว่าฉันคาดว่าจะให้คะแนนคำตอบอย่างเป็นกลาง อย่างไรก็ตามฉันคิดว่าคำถามทำให้ชัดเจน: อันดับแรกจำนวนบรรทัด cruft; ทำลายความสัมพันธ์นั้นโดยจำนวนตัวอักษร cruft; จากนั้นตามจำนวนบรรทัดโครงสร้างพื้นฐานจากนั้นตามด้วยจำนวนอักขระโครงสร้างพื้นฐาน ฉันไม่ได้คาดหวังว่าจะมีวิธีแก้ปัญหาที่ทำให้เกิดช่องว่างในการโหลดเช่นโซลูชันแรกของจิมมี่ ฉันจะเปลี่ยนคำถามเล็กน้อยเพื่อให้ชัดเจนว่าเป็นสิ่งที่ไม่พึงประสงค์ (ขออภัยสำหรับการเปลี่ยนแปลงเสาประตูเล็กน้อย แต่ฉันไม่คิดว่ามันจะส่งผลกระทบต่อวิธีแก้ปัญหาที่สองของเขาหรือรุ่นใด ๆ ของคุณจนถึงตอนนี้)
jez

ดูเหมือนว่าคำตอบของเราจะมาบรรจบกัน ;-) คุณมีความได้เปรียบในการทำคะแนนด้วยการใช้ heredoc เป็นสิ่งสุดท้ายที่#จำเป็น?
บาดเจ็บทางดิจิทัล

4

คะแนน 0 cruft + 4 สายอินทรา + 32 ตัวอักษรอินทรา ตกลง & CRLF

นี่คือสิ่งที่ฉันพบในบล็อกนี้โดยใช้บิต Amiga และบรรทัดที่ไม่จำเป็นอื่น ๆ ที่นำออกมา ฉันซ่อนบรรทัด DOS ในเครื่องหมายคำพูดที่คอมเม้นต์แทนการใช้\line ต่อเพื่อให้สามารถทำงานกับทั้ง CRLF และ LF

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

ด้วยการสิ้นสุดสาย DOS CRLF หรือ * nix LF สามารถใช้กับ Ubuntu, OSX และ wine:

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

หากต้องการสร้างสิ่งนี้อย่างแน่นอน (ด้วย CRLF) บนเครื่อง * nix (รวมถึง OSX) ให้วางรายการต่อไปนี้ลงในเทอร์มินัล:

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

ดูดี! dosixเป็นชื่อที่ดีเช่นกัน แต่สำหรับ Mac ของฉัน (OS 10.9.4, Kernel เวอร์ชันดาร์วิน 13.3.0, GNU ทุบตีรุ่น 3.2.51) มันล้มเหลวในการทำงานด้วย: ./dosix.cmd: line 13: syntax error: unexpected end of file ความคิดใดทำไม?
jez

@jez ตรวจสอบให้แน่ใจว่าคุณบันทึกไฟล์ที่เข้ารหัสด้วย UTF-8 และคงการสิ้นสุดบรรทัด Windows!
แมว

อ๊ะเกิดขึ้นเพราะฉันไม่รู้ว่าจุดสิ้นสุดของ Windows และใช้เวอร์ชันแรก
jez

โปรดทราบว่าคุณสามารถป้อนอักขระ CR ใน Bash โดยใช้การแทรก (หรือ Cv), ป้อน (หรือ Cm)
jimmy23013

@jez ดังนั้นคะแนนนี้เป็น 0 cruft lines + 4 infrastructure lines + 32 chars โครงสร้างพื้นฐาน ควรรวมตัวเลขเหล่านี้ในลักษณะที่มีความหมายใด ๆ เพื่อสร้างคะแนนเดียวสำหรับการเปรียบเทียบ?
บาดเจ็บทางดิจิทัล

2

ฉันจะโพสต์วิธีแก้ปัญหาที่ฉันใช้อยู่แล้วเพราะมันถูกตีแล้ว มารยาทมันของเพื่อนร่วมงานของผมที่ผมคิดว่าจะต้องมีการอ่านรายการบล็อกเดียวกับดิจิตอลบาดเจ็บ

#!/bin/sh # >NUL 2>&1
echo \
@goto c \
>/dev/null
echo "Hello Posix!"
exit
:c
@echo Hello Windows!
  • Windows cruft: 5 บรรทัด (ที่สองช่องว่าง) / 30 ตัวอักษร
  • OSX cruft: 0
  • โครงสร้างพื้นฐาน: 6 บรรทัด / 52 ตัวอักษร
  • ความเข้ากันได้ CRLF: เฉพาะเมื่อล่ามที่มีชื่ออยู่ใน#!บรรทัดไม่สนใจ (ดังนั้นสำหรับล่ามมาตรฐานเช่นshและเพื่อน ๆ มันล้มเหลว)

บน POSIX สคริปต์จะเริ่มต้นด้วยเสมอ#!ซึ่งหมายความว่าคุณเป็นคำตอบเดียวที่เป็นสคริปต์ที่ถูกต้องในระบบ POSIX แน่ใจว่าบางคนอื่นอาจทำงานถ้า - แต่ถ้าพวกเขาเริ่มต้นจากเปลือกที่มีวิธีแก้ปัญหาสำหรับสคริปต์ผิดพลาด
kasperd

ดีแล้วที่รู้! ฉันเดาว่าฉันคลุมเครือในเกณฑ์ที่เข้มงวดสำหรับการปฏิบัติตาม POSIX เป้าหมายที่แท้จริงของฉันคือการมีไฟล์สคริปต์ที่ทำงานได้ "ออกนอกกรอบ" บน "ระบบเดสก์ท็อปที่ทันสมัย" ส่วนใหญ่ "ไม่ว่ามันจะหมายถึงอะไร - Windows 7/8/10, Ubuntu, OSX ... สากลเป็นวิธีการแก้ปัญหา ฉันสงสัยหรือไม่ อย่างไรก็ตามฉันจะไม่มอบคะแนนให้กับตัวเอง :-)
jez

ฉันไม่ได้สังเกตว่าทั้งคำตอบและคำถามถูกเขียนโดยบุคคลเดียวกัน ฉันคิดว่าเชลล์ทั้งหมดที่ฉันทำงานด้วยมีวิธีแก้ปัญหาสำหรับ#!บรรทัดที่หายไปแต่พวกเขาจะใช้เชลล์ที่แตกต่างกันในการตีความสคริปต์ นั่นหมายความว่า "สคริปต์" ซึ่งไม่ได้ขึ้นต้นด้วย#!จะต้องมีความถูกต้องไม่ใช่แค่หนึ่งเชลล์ แต่ทุกเชลล์ที่ตีความได้อย่างน่าเชื่อถือ แต่ยิ่งแย่ไปกว่านั้นมันใช้งานได้เมื่อเริ่มต้นจากเปลือกหอยอื่น สคริปต์ดังกล่าวอาจทำงานได้จากบรรทัดคำสั่ง แต่ไม่ใช่ในบริบทที่คุณตั้งใจจะใช้งานในที่สุด
kasperd

ขอบคุณนี่คือสิ่งที่ให้ความรู้และเป็นสิ่งที่ฉันหวังว่าจะได้เรียนรู้โดยเริ่มต้นความท้าทายนี้ สำหรับกรณีที่สิ่งนี้จะ (หรืออาจมีความสำคัญ) #!บรรทัดในคำตอบที่แก้ไขของฉัน (1 สายโครงสร้างพื้นฐานที่มี 21 ตัวอักษร) สามารถรวมกับคำตอบของใครก็ได้ที่ค่าใช้จ่าย cruft เฉพาะ Windows 2 บรรทัด (ที่หนึ่งว่างเปล่า) หรือ 23 ตัวอักษร
jez

2

สรุป / สังเคราะห์คำตอบและอภิปราย

สนุกมากและฉันเรียนรู้มาก

cruft เฉพาะสำหรับ Windows บางอย่างอาจหลีกเลี่ยงไม่ได้หากในระบบ POSIX ของคุณคุณต้องเริ่มต้นสคริปต์ด้วย#!บรรทัด หากคุณไม่มีทางเลือกนอกจากทำสิ่งนี้ให้ทำตามบรรทัดนี้:

#!/bin/sh # 2>NUL

น่าจะเป็นสิ่งที่ดีที่สุดที่จะได้รับ มันทำให้เกิดหนึ่งบรรทัดว่างและ cruft บรรทัดเดียวที่จะออกในคอนโซล Windows อย่างไรก็ตามคุณอาจหนีไปได้โดยไม่ต้องมี#!บรรทัด: ในระบบส่วนใหญ่หนึ่งในล่ามเชลล์ปกติจะจบลงด้วยการเรียกใช้สคริปต์ (ปัญหาคือว่ามันไม่สามารถคาดเดาได้ในระดับสากลซึ่งล่ามนั้นจะขึ้นอยู่กับมัน แต่จะ ไม่จำเป็นต้องเหมือนกันเชลล์ที่คุณใช้เพื่อเรียกใช้คำสั่ง)

นอกเหนือจากบรรทัดแรกที่ยุ่งยากนั้นยังมีวิธีแก้ปัญหา cruftless ที่แยบยลจริงๆ ผลงานที่ชนะโดยjimmy23013ประกอบด้วยเพียงสองบรรทัดโครงสร้างพื้นฐานสั้นและใช้ประโยชน์จากบทบาทที่สองของ:ตัวละครในการใช้สาย "เงียบ" บนแพลตฟอร์มทั้งสอง (เป็นde-พฤตินัยไม่มี -op ในshและเพื่อน ๆ และเป็นฉลาก เครื่องหมายในcmd.exe):

:<<@exit/b

:: Arbitrary Windows code goes here

@exit/b
#
# Arbitrary POSIX code goes here 

มีความเป็นไปได้ที่จะทำให้สคริปต์ทำงานบนระบบ POSIX แม้จะมีการสิ้นสุดบรรทัด CRLF แต่การทำเช่นนี้สำหรับล่ามส่วนใหญ่คุณต้องจบทุกบรรทัดในส่วน POSIX ของคุณ (แม้แต่บรรทัดว่าง) ด้วยความคิดเห็นหรืออักขระความคิดเห็น

ในที่สุดนี่คือสองตัวแปรในโซลูชันที่ฉันพัฒนาขึ้นตามการป้อนข้อมูลของทุกคน พวกเขาอาจจะเกือบดีที่สุดในโลกเพราะพวกเขาลดความเสียหายจากการขาด#!และทำให้การเข้ากันได้กับ CRLF ราบรื่นยิ่งขึ้น ต้องการโครงสร้างพื้นฐานเพิ่มเติมสองบรรทัด บรรทัดเดียว (มาตรฐาน) จะต้องถูกตีความโดยเชลล์ POSIX ที่ไม่สามารถคาดเดาได้และบรรทัดนั้นช่วยให้คุณสามารถเลือกเชลล์สำหรับสคริปต์ที่เหลือ ( bashในตัวอย่างต่อไปนี้):

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

ส่วนหนึ่งของความสวยงามของโซลูชัน heredoc เหล่านี้คือพวกเขายังคงทนทานต่อ CRLF: ตราบใดที่<<:Zมาถึงจุดสิ้นสุดของบรรทัดโปรเซสเซอร์ heredoc จะมองหาและจะพบโทเค็น:Z\r

คุณสามารถกำจัดความคิดเห็นที่น่ารำคาญในตอนท้ายและยังคงไว้ซึ่งความทนทานของ CRLF โดยการแยก\rตัวละครออกก่อนที่จะส่งผ่านเส้นไปยังเปลือกหอย สถานที่แห่งนี้มีศรัทธามากขึ้นในเชลล์ที่คาดเดาไม่ได้ (ควรใช้{ tr -d \\r|bash;}แทน(tr -d \\r|bash)วงเล็บปีกกา แต่เป็นรูปแบบของ bash-only ไวยากรณ์):

:<<@GOTO:Z

@echo Hello Windows!

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

echo "Hello POSIX!"
ps

:Z

แน่นอนวิธีการนี้จะเสียสละความสามารถในการป้อนข้อมูล stdin ลงในสคริปต์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.