เคล็ดลับการตีกอล์ฟแบบแบตช์


14

Windows Batch (CMD) เป็นภาษาที่เหมาะสมที่สุดสำหรับการตีกอล์ฟ

หลีกเลี่ยงตัวอักษรขึ้นบรรทัดใหม่ หากคุณกำลังมองหารหัสที่สั้นที่สุดเป็นไบต์ซึ่งตรงข้ามกับตัวอักษรคุณจะต้องกำจัดการขึ้นบรรทัดใหม่ที่ไม่จำเป็นออกไป (อักขระขึ้นบรรทัดใหม่ = 2 ไบต์) คุณสามารถใช้การ&ดำเนินการนี้เพื่อตัดหนึ่งไบต์สำหรับแต่ละคำสั่ง

echo Hello&echo World.

การตั้งค่าตัวแปร เมื่อตั้งค่าตัวแปรโดยใช้สวิตช์setตัวแยกวิเคราะห์จะละเว้นช่องว่าง

set /a a+=1
set /p b="User Input: "
:: Will be handled the same as..
set/aa+=1
set/pb="User Input: "

โปรดทราบว่ากฎการแยกวิเคราะห์เดียวกันไม่ได้ใช้กับคำสั่งทั้งหมด - ตัวอย่างเช่นสำหรับลูปต้องใช้ช่องว่าง ยกเว้นระหว่างset, string, or command(คือสิ่งที่อยู่ภายในวงเล็บ) doและคำว่า

for /f %%a in (file.txt)do ...

การแสดงออกทางคณิตศาสตร์อย่างง่าย นอกจากนี้สังเกตเห็นการแสดงออกที่ฉันใช้สำหรับการเพิ่มขึ้นในset /aคำสั่ง สำหรับการแสดงออกทางคณิตศาสตร์อย่างง่ายใช้+= -= *= /=แทน set /a a=%a%+1(ตัวอย่าง)

ออกคำสั่งการชุมนุม ในการรับเอาต์พุตของคำสั่งบางครั้งอาจเป็นประโยชน์ในการส่งออกและอ่านจากไฟล์ซึ่งคุณอาจใช้สำหรับลูปเพื่อรวบรวมเอาต์พุต:

for /f %%a in ('echo test') do set a=%%a
:: Can be shortened to
echo test>f&set/pa=<f

echo testส่ง stdout ไปยังไฟล์ที่เรียกว่า F, >fเริ่มต้นคำสั่งใหม่และได้รับเนื้อหาของไฟล์ในตัวแปร& set/pa=<fเห็นได้ชัดว่านี่ไม่ได้มีประโยชน์เสมอไป แต่มันอาจเป็นไปได้เมื่อคุณต้องการเพียงแค่เอาต์พุตบรรทัดเดียว

ออกคำสั่ง เมื่อระงับเอาต์พุตคำสั่งให้ใช้@ก่อนคำสั่งยกเว้นว่าคุณต้องการระงับมากกว่า 9คำสั่งซึ่งในกรณีนี้ให้ใช้@echo offที่จุดเริ่มต้นของสคริปต์ของคุณ @echo offมีความยาว 9 ไบต์และโดยทั่วไปแล้วจะบันทึกเพิ่มเติมด้วยสคริปต์ที่ยาวขึ้น

คำสั่งมักจะทำมากกว่าสิ่งที่ชัดเจน - คิดเกี่ยวกับสิ่งที่คำสั่งของคุณกำลังทำ ตัวอย่างเช่น; หากคุณต้องการตั้งค่าตัวแปรและ echo ตัวแปรอื่นแทน:

set a=OUTPUT
echo %a%
echo test>f
set /p b=<f

คุณสามารถใช้คำสั่ง set ด้วย/pสวิตช์เพื่อส่งออก%a%ให้คุณ

set a=OUTPUT
echo test>f
set /p b=%a%<f

สนามกอล์ฟที่สมบูรณ์ ...

set a=OUTPUT&echo test>f&set/pb=%a%<f

คู่ของ expamples เอ - นับผลรวมของตัวเลขทั้งหมด - การคาดคะเนของ Goldbach

เคล็ดลับอื่น ๆ มีความนิยมมากกว่า - ฉันจะอัปเดตสิ่งนี้ต่อไปหากฉันคิดอย่างอื่น


16
กรุณาโพสต์ส่วนคำตอบของสิ่งนี้เป็นคำตอบไม่ใช่ส่วนหนึ่งของคำถาม
ไม่ใช่ชาร์ลส์

@Charles ฉันค่อนข้างแน่ใจว่าฉันได้ทำสิ่งนี้เป็นรูปแบบที่ยอมรับได้สำหรับ 'คำถามเคล็ดลับ' คนอื่นสามารถเพิ่มคำตอบด้วยเคล็ดลับของตนเอง
ลุง

คำตอบ:


4

เคาน์เตอร์

เมื่อใดก็ตามที่คุณมีตัวแปรที่จะทำหน้าที่เป็นตัวนับเริ่มจาก0คุณอาจต้องการเขียน

set count=0
set/acount+=1

; อย่างไรก็ตามคุณสามารถกำจัดบรรทัดแรกเพราะเมื่อใดก็ตามที่set/aใช้กับตัวแปร unset ค่าของมันจะถือว่าเป็น0

set/acounter+=1

บล็อครหัส

มีหลายวิธีที่คุณสามารถโกนทิ้งได้ไม่กี่ไบต์เมื่อคุณต้องใช้บล็อคโค้ด

เมื่อใดก็ตามที่คุณเปิดบล็อกโค้ดคุณไม่จำเป็นต้องแทรกตัวแบ่งบรรทัดก่อนโค้ดบรรทัดแรกในบล็อกนั้น วงเล็บปิดไม่จำเป็นต้องอยู่ในบรรทัดของมันเอง

If %a%==%b% (
     echo true
) else (
    echo false
)

สามารถเล่นกอล์ฟถึง

If %a%==%b% (echo true)else (echo false)

การพิมพ์โดยไม่ขึ้นบรรทัดใหม่

รูปแบบทั่วไปของสิ่งนี้คือ

echo|set/p=text

แต่คุณสามารถบันทึก 2 ไบต์เปลี่ยนechoเป็นcd

cd|set/p=text

2
@ ankp-morpork เฮ้ฉันสายไปหน่อย แต่ฉันต้องการแจ้งให้คุณทราบว่าifถ้อยแถลงนั้นสามารถตีกอล์ฟต่อไปได้ สิ่งที่ดีที่สุดควรเป็น:if %a%==%b% (echo true)else echo false
stevefestl

3

เครื่องหมาย

แม้ว่าจะทำให้โค้ดดูสั้นลงเนื่องจากใช้บรรทัดน้อยลง แต่ใช้อักขระมากเท่าบรรทัดใหม่ ซึ่งหมายความว่า

echo a&echo b

ตราบใดที่

echo a
echo b

เพื่อให้รหัสของคุณสามารถอ่านได้โดยไม่สูญเสียอักขระ

อาจมีข้อยกเว้นเนื่องจากเครื่องมือแก้ไขข้อความบางตัวรวมฟีดบรรทัดและ Carridge Return สำหรับแต่ละบรรทัดใหม่


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

2
carraige return linefeed ของ Window เป็นตัวละครสองตัวและผู้แก้ไขข้อความจำนวนมากจะนับเป็นสอง แต่เมื่อฉันเริ่มตอบคำถามกอล์ฟครั้งแรกหนึ่งในความคิดเห็นที่เหลือกล่าวว่าในตอนท้ายบรรทัด PPCG มักจะนับเป็นตัวละครหนึ่งตัว
Jerry Jeremiah

2
linefeeds สไตล์ Unix จะทำงานได้ดีในสคริปต์ CMD อย่างน้อยใน Windows รุ่นล่าสุด
2428118

1
ในความเป็นจริง CMD แม้จะลบอักขระ CR ก่อนที่จะแยกวิเคราะห์: stackoverflow.com/questions/4094699/ …
schnaader

3

พิมพ์ผลการคำนวณตัวเลขโดยตรง

หากความท้าทายต้องการให้คุณส่งออกตัวเลขที่ต้องคำนวณคุณสามารถใช้cmd/c set/aเพื่อส่งออกผลลัพธ์ของการคำนวณโดยตรงแทนที่จะบันทึกการคำนวณแล้วสะท้อนออกมา ตัวอย่าง:

@set/a a=%1+%2
@echo %a%

กลายเป็น

@cmd/cset/a%1+%2

แก้ไข: เห็นได้ชัดว่าไม่จำเป็นต้องเว้นวรรคเลยประหยัดอีก 2 ไบต์


2

การขยายตัวล่าช้า

แทนที่จะใช้ความยาวsetLocal enableDelayedExpansionคุณสามารถใช้cmd /v on(หรือcmd/von ) ซึ่งจะเริ่มล่ามใหม่โดยเปิดใช้งานการขยายตัวแปรล่าช้า

ฉันยังไม่ได้ใช้สิ่งนี้ดังนั้นฉันจึงไม่มีตัวอย่างใด ๆ แต่คุณสามารถใช้สิ่งนี้ร่วมกับ/cสวิตช์ ตัวอย่าง:

@cmd/von/cset test=test^&echo !test!

สังเกตการใช้กะรัตก่อนเครื่องหมายแอมเปอร์แซนด์ หากคุณจำเป็นต้องใช้เครื่องหมายแอมเปอร์แซนด์หลายตัวหรืออักขระพิเศษอื่น ๆ คุณอาจปิดล้อมทุกอย่างได้ดีกว่าหลังจาก/cสวิตช์ในเครื่องหมายคำพูด:

@cmd/von/c"set test=test&set test1=test1&echo !test! !test1!"

วิธีนี้ยังมีข้อได้เปรียบในการใช้@อักขระเพียงตัวเดียวเพื่อปกปิดการป้อนข้อมูลทั้งหมดและสามารถใช้โดยไม่ต้อง/vonเป็นทางเลือกที่สั้นกว่า@echo off(หรือหลายตัวเลือก)@สัญลักษณ์ตัว)

9 ตัวอักษร: @echo off
6 ตัว:@cmd/c

สำหรับสคริปต์ที่มีความยาวมากกว่าซึ่งคุณไม่สามารถทำได้ในหนึ่งบรรทัดคุณสามารถทำสิ่งต่อไปนี้เพื่อบันทึกไบต์บางส่วน:

@!! 2>nul||cmd/q/v/c%0&&exit/b

หรือไม่อัปโหลด:

@!! 2>nul || cmd /q /v on /c %0 && exit/b

แทนที่ @echo off&setLocal enableDelayedExpansionด้วยข้างต้น

เมื่อคุณรันสคริปต์ครั้งแรกของคุณ!!จะไม่ขยายเลยดังนั้นคุณจะได้รับข้อผิดพลาดเนื่องจาก"!!"ไม่ใช่คำสั่ง เอาต์พุตข้อผิดพลาดจะถูกไพพ์ไปที่ nul ( 2>nul) เมื่อ 'คำสั่ง' แรกนี้ล้มเหลว ( ||) จะเรียกใช้อินสแตนซ์ใหม่ของ cmd ซึ่งเรียกไฟล์แบตช์ของตัวเอง (ใช้/v (on)เพื่อเปิดใช้งานการขยายตัวล่าช้าและ/qเพื่อปิดเสียงก้อง) จากนั้นจะขยายไปยังไม่มีอะไรเป็นมีตัวแปรที่เรียกว่าไม่มี!! <NULL>ส่วนที่เหลือของสคริปต์ของคุณจะทำงาน หลังจากนั้นมันจะกลับสู่อินสแตนซ์ดั้งเดิมของ cmd และ ( &&) ออกโดยมี/bเงื่อนไขเพื่อให้หน้าต่างเปิดอยู่ (ทางออกคือมันจะไม่ทำงานต่อในสคริปต์ของคุณในบริบทของอินสแตนซ์ cmd แรกโดยมี echo เปิดและปิดการขยายออกล่าช้า)


สำหรับสิ่งนี้การรันไฟล์แบตช์ด้วยcmd /q /v on /c <filename>ควรนับเป็น 2 ไบต์เท่านั้นเนื่องจากเป็น "แฟล็ก" สองตัวที่คล้ายกับแฟล็ก Perl -pIซึ่งจะนับเป็น 2 ไบต์พิเศษเท่านั้น
Artyer

1

สตริงซ้ำ

ตั้งค่าการบล็อกรหัสซ้ำในตัวแปรที่จำนวนไบต์ที่ใช้ในการตั้งค่าตัวแปร + จำนวนไบต์เพื่อส่งออกตัวแปรมีค่าน้อยกว่าจำนวนไบต์เพียงแค่เรียกใช้รหัสโดยตรง

ตัวอย่างเช่นดู: วาดชุดค่าผสมที่รวมกันได้สูงสุด 100

คุณประหยัด 1 ไบต์ต่อการใช้งานของชุดคำสั่งถ้าคุณสร้างตัวแปร (ชื่อที่มีตัวละครตัวหนึ่งเช่น "s") set<space>ซึ่งประกอบด้วย สิ่งนี้จะสร้างมูลค่าหากคุณใช้คำสั่ง set มากกว่า 12 ครั้ง (หมายเหตุมีอักขระที่ท้ายของสตริงset s=set)

set s=set 
%s%a=1
%s%b=2
%s%c=3
%s%d=4
%s%e=5
%s%f=6
%s%g=7
%s%h=8
%s%i=9
%s%j=10
%s%k=11
%s%l=12
%s%m=13

ด้านบนคือ 1 ไบต์สั้นกว่า ..

set a=1
set b=2
set c=3
set d=4
set e=5
set f=6
set g=7
set h=8
set i=9
set j=10
set k=11
set l=12
set m=13

นี่อาจเป็นตัวอย่างที่ไม่ดีนัก - แต่มันก็ได้ประเด็นมา


1

เริ่มต้นของสตริง

สัญกรณ์สารสกัดย่อยของตัวแปร%var:~start,end% varอย่างไรก็ตามถ้าstartเป็นเช่น0นั้นคุณสามารถละเว้นได้ทั้งหมด เรารู้อยู่แล้วว่าคุณสามารถละเว้นได้,endถ้าคุณต้องการให้สตริงที่เหลือซึ่งทำให้%var:~%คำพ้องความหมายไร้ประโยชน์เกือบ%var%ยกเว้นว่ามันจะส่งกลับ~เมื่อ%var%ว่างเปล่า (บางทีคุณสามารถใช้มันในการทดสอบ: if %var:~%==~?)


ฉันชอบประโยคสุดท้ายของคุณที่เตือนเราว่าสิ่งนี้จะช่วยให้คุณประหยัดราคาได้ :) +1 สำหรับสิ่งนั้น
stevefestl

1

ทำให้IF EQUข้อความสั้นลง

if %a% equ %b% do_something
if %a%==%b% do_something

ใช้==แทนการ equ บันทึก3ไบต์


ทำให้คำพูดสั้นลง IFงบ

นี่คือแบบดั้งเดิมที่เรียกว่า "ความปลอดภัยมากขึ้น" ifที่เปรียบเทียบ

if "%a%"=="%b%" do_something

ในการย่อคำสั่งนี้ให้ทำดังต่อไปนี้เมื่ออินพุตสามารถเป็นตัวอักษรและตัวเลข / ว่างได้เท่านั้น :

if %a%.==%b%. do_something

กำลังบันทึกทั้งหมด2ไบต์


ความท้าทายที่ต้องใช้ผลผลิต

หากคำถามพูดถึงสิ่งที่ชอบ:

เอาต์พุตอย่างน้อย 1 ตัวอักษรที่มองเห็นได้

จากนั้นคุณสามารถทำสิ่งนี้:

cd

แสดงไดเรกทอรีปัจจุบันไปยังcdSTDOUT


GOTOไอเอ็นจีฉลาก

ต่อไปนี้เป็นวิธีการในgotoการติดป้ายกำกับเรียงตามลำดับจากน้อยไปมาก

goto :l
goto l
goto:l

วิธีการดังกล่าวบันทึก1ไบต์


1
หรือคุณสามารถทำได้goto:lซึ่งจะช่วยประหยัด 1 ไบต์เดียวกันและมีโบนัสเพิ่มเติมในการรักษาลำไส้ใหญ่ของคุณเอาไว้
Matheus Avellar

@MatheusAvellar: ฉันได้เพิ่มเนื้อหาตามความคิดเห็นของคุณ
stevefestl

1

เว้นช่องว่างระหว่างคำสั่งและพารามิเตอร์ด้วยเครื่องหมายทับ

ขออภัยเกี่ยวกับชื่อที่ไม่เป็นทางการ สิ่งที่ฉันพยายามทำคือสำหรับบางคำสั่ง (ไม่ใช่ทั้งหมด) ของ Windows คุณสามารถเว้นช่องว่างระหว่างชื่อคำสั่ง / โปรแกรมและพารามิเตอร์ตราบใดที่พารามิเตอร์นั้นเริ่มต้นด้วยเครื่องหมายทับ ตัวอย่างเช่น:

for /f %%G in ...

กลายเป็น

for/f %%G in ...

-1 ไบต์!

Piping output แทนที่จะใช้ ERRORLEVEL

การใช้ ERRORLEVEL เพื่อตรวจสอบว่าคำสั่งรันอย่างถูกต้องไม่ใช่วิธีที่สั้นที่สุดหรือสง่างามที่สุด แต่คุณสามารถส่งออกท่อ นี้ทำงานดังต่อไปนี้ (จำไว้ว่าคำสั่งใด ๆ หลังจากที่&&ผู้ประกอบการดำเนินการเฉพาะในกรณีที่คำสั่งก่อนที่จะ&&วิ่งโดยไม่มีข้อผิดพลาดคำสั่งใด ๆ หลังจากที่||ผู้ประกอบการในทางกลับกันจะทำงานเฉพาะถ้าคำสั่งก่อนที่จะทำงานไม่ถูกต้อง :

net session>nul
if %errorlevel%==0 (echo 1) else (echo 0)

สิ่งนี้อาจถูกแทนที่ด้วย:

net session>nul&&echo 1||echo 0

-26 ไบต์ว้าว! โปรดทราบว่าสิ่งนี้ไม่ทำงานกับคำสั่งเช่นchoiceที่ข้อผิดพลาดมีค่าพิเศษตามการป้อนข้อมูลบางอย่าง

ขอแสดงความนับถือ
Gabe


1

การใช้วงเล็บอย่างมีประสิทธิภาพ

สวัสดีอีกครั้ง,

ขออภัยที่โพสต์คำตอบที่สอง แต่ฉันรู้สึกว่ามันสมควรได้รับมัน ฉันสังเกตเห็นว่าผู้คนมักใช้วิธีต่อไปนี้เพื่อแสดงเอาต์พุตคำสั่งโดยไม่แสดงC:\Windows\System32>echo fooบรรทัดที่น่ารำคาญก่อนแต่ละคำสั่ง
วิธีแรก (โดยใช้echo off):

@echo off
echo foo
echo bar
echo foobar
echo barfoo

วิธีที่สอง:

@echo foo
@echo bar
@echo foobar
@echo barfoo

อย่างไรก็ตามวิธีการเหล่านี้ไม่สั้นอย่างใดอย่างหนึ่งดังต่อไปนี้:

@(echo foo
echo bar
echo foobar
echo barfoo)

ค่อนข้างมีประโยชน์ใช่ไหม ในบันทึกอื่น ๆ สิ่งนี้สามารถใช้เพื่อไพพ์เอาท์พุทหลายบรรทัดไปยังไฟล์หรืออุปกรณ์ได้อย่างง่ายดาย ตัวอย่างเช่นรหัสยาวนี้:

echo foo>file.txt
echo bar>file.txt
echo foobar>file.txt
echo barfoo>file.txt

สั้นลงอย่างมีนัยสำคัญ:

(echo foo
echo bar
echo foobar
echo barfoo)>file.txt

ขอบคุณที่อ่านคำตอบที่ค่อนข้างยาวและฉันหวังว่านี่จะช่วยคุณได้ ขอแสดงความนับถือ
Gabe


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