Tipps zum Golfen in Batch

14

Windows Batch (CMD) ist wahrscheinlich die am wenigsten geeignete Sprache für das Code-Golfen.

Vermeiden Sie Zeilenumbrüche . Wenn Sie nicht nach Zeichen, sondern nach dem kürzesten Code in Byte suchen, müssen Sie alle unnötigen Zeilenumbrüche (Zeilenumbrüche = 2 Byte) vermeiden. Mit &dieser Operation können Sie für jeden Befehl ein Byte abschneiden.

echo Hello&echo World.

Variablen setzen . Beim Setzen von Variablen mit Hilfe von Schaltern setignoriert der Parser Leerzeichen.

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

Beachten Sie, dass die gleichen Parser-Regeln nicht für alle Befehle gelten - beispielsweise für Schleifen, die Leerzeichen erfordern. Außer zwischen dem set, string, or command(dh was sich in den Klammern befindet) und dem Wort do.

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

Einfache mathematische Ausdrücke . Beachten Sie auch den Ausdruck, den ich zum Inkrementieren des set /aBefehls verwendet habe. Für einfache mathematische Ausdrücke verwenden Sie += -= *= /=statt (zum Beispiel) set /a a=%a%+1.

Befehlsausgabe wird gesammelt . Um die Ausgabe eines Befehls zu erhalten, kann es manchmal nützlich sein, in eine Datei auszugeben und daraus zu lesen, wo Sie andernfalls möglicherweise eine for-Schleife verwendet haben, um die Ausgabe zu erfassen:

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

echo testSenden Sie stdout an eine Datei mit dem Namen f, >fstarten Sie einen neuen Befehl &und rufen Sie den Inhalt der Datei in einer Variablen ab set/pa=<f. Offensichtlich ist das nicht immer nützlich. Dies kann jedoch der Fall sein, wenn Sie nur eine einzige Ausgabezeile benötigen.

Befehlsausgabe . Verwenden @Sie beim Unterdrücken der Befehlsausgabe vor den Befehlen, es sei denn, Sie müssen mehr als 9 Befehle unterdrücken. Verwenden Sie in diesem Fall @echo offzu Beginn Ihres Skripts. @echo offist 9 Bytes lang und spart daher in der Regel mehr Bytes bei längeren Skripten.

Befehle tun oft mehr als nur das, was offensichtlich ist - denken Sie darüber nach, was Ihre Befehle tun. Beispielsweise; Wenn Sie eine Variable setzen und eine andere Variable ausgeben müssen, anstatt:

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

Sie können den Befehl set mit dem /pSchalter verwenden, um %a%für Sie auszugeben .

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

Völlig golfen ...

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

Ein paar Beispiele - Summe aller Ziffern zählen - Goldbachs Vermutung .

Alle anderen Tipps sind mehr als willkommen - ich werde dies weiter aktualisieren, wenn mir etwas anderes einfällt.

unclemeat
quelle
16
Bitte posten Sie die Antwortteile als Antwort, nicht als Teil der Frage.
Nicht dass Charles
@Charles Ich bin mir ziemlich sicher, wie ich das gemacht habe, ist ein akzeptables Format für eine "Tippfrage". Andere Personen können Antworten mit eigenen Tipps hinzufügen.
Unclemeat

Antworten:

4

Zähler

Wann immer Sie eine Variable haben, die als Zähler fungiert, 0möchten Sie vielleicht schreiben

set count=0
set/acount+=1

; Sie können jedoch die ersten Zeilen entfernen, da immer dann, wenn set/aeine nicht gesetzte Variable verwendet wird, angenommen wird, dass ihr Wert gleich ist0

set/acounter+=1

Codeblöcke

Es gibt eine Reihe von Möglichkeiten, wie Sie ein paar Bytes sparen können, wenn Sie Codeblöcke verwenden müssen.

Wenn Sie einen Codeblock öffnen, müssen Sie vor der ersten Codezeile in diesem Block keinen Zeilenumbruch einfügen. Die schließenden Klammern müssen auch nicht in einer eigenen Zeile stehen.

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

kann golfen werden

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

Drucken ohne Zeilenumbruch

Das übliche Muster dafür ist

echo|set/p=text

aber können Sie sparen 2 Bytes Wechsel echozucd

cd|set/p=text
Ankh-Morpork
quelle
2
@ ankp-morpork Hey, ich bin ein bisschen spät dran. Aber ich möchte Sie darüber informieren, dass die ifAussage weiter golfen werden kann. Das beste sollte sein:if %a%==%b% (echo true)else echo false
Stevefestl
3

Etzeichen

Obwohl & den Code kürzer erscheinen lässt, da weniger Zeilen verwendet werden, verwendet er genauso viele Zeichen wie eine neue Zeile. Das bedeutet, dass

echo a&echo b

ist so lang wie

echo a
echo b

So bleibt Ihr Code lesbar, ohne Zeichen zu verschwenden.

Es kann Ausnahmen geben, da einige Texteditoren Zeilenvorschub und Zeilenumbruch für jede neue Zeile kombinieren.

kitcar2000
quelle
Ich habe dies in den ursprünglichen Beitrag aufgenommen, da ein Zeilenumbruch in jedem von mir verwendeten Texteditor zwei Byte lang ist. Vielen Dank, dass Sie diese Klarstellung hinzugefügt haben.
Unclemeat
2
Window's Carraige Return Linefeed besteht aus zwei Zeichen und viele Texteditoren zählen es als zwei, aber als ich anfing, Golffragen zu beantworten, sagte einer der Kommentare, dass in PPCG Zeilenenden immer als ein Zeichen gezählt werden.
Jerry Jeremiah
2
Zeilenvorschübe im Unix-Stil funktionieren in CMD-Skripten einwandfrei, zumindest in neueren Windows-Versionen.
user2428118
1
Tatsächlich entfernt CMD CR-Zeichen sogar vor dem Parsen: stackoverflow.com/questions/4094699/…
schnaader 17.10.17
3

Drucken Sie das Ergebnis einer numerischen Berechnung direkt aus

Wenn die Abfrage die Ausgabe einer zu berechnenden Zahl erfordert, können Sie cmd/c set/adas Ergebnis der Berechnung direkt ausgeben, anstatt die Berechnung zu speichern und anschließend zu wiederholen. Beispiel:

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

wird

@cmd/cset/a%1+%2

Bearbeiten: Anscheinend sind überhaupt keine Leerzeichen erforderlich, wodurch 2 weitere Bytes eingespart werden.

Neil
quelle
2

Verzögerte Expansion

Anstelle der Verwendung von longy können setLocal enableDelayedExpansionSie cmd /v on(oder cmd/von) verwenden, um einen neuen Interpreter mit aktivierter verzögerter Variablenerweiterung zu starten.

Ich muss dies noch implementieren, damit ich keine Beispiele habe, aber Sie können dies in Verbindung mit dem /cSchalter verwenden. Beispiel:

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

Beachten Sie die Verwendung des Karats vor dem kaufmännischen Und. Wenn Sie mehrere kaufmännische Und-Zeichen oder andere Sonderzeichen verwenden müssen, sollten Sie nach dem /cWechsel alles in Anführungszeichen setzen:

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

Diese Methode hat auch den Vorteil, dass nur ein @Zeichen zum Maskieren aller Eingaben verwendet werden muss, und kann daher ohne /voneine kürzere Alternative zu @echo off(oder mehreren @Symbolen) verwendet werden.

9 Zeichen: @echo off
6 Zeichen:@cmd/c

Bei längeren Skripten, die Sie nicht in einer Zeile ausführen können, können Sie die folgenden Schritte ausführen, um einige Bytes zu sparen:

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

Oder ungolfed:

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

Ersetzen Sie @echo off&setLocal enableDelayedExpansionmit dem oben.

Wenn Sie das Skript zum ersten Mal ausführen, !!wird es überhaupt nicht erweitert, sodass Sie einen Fehler erhalten, da "!!"es sich nicht um einen Befehl handelt. Die Fehlerausgabe wird dann an nul ( 2>nul) weitergeleitet. Wenn dieser erste 'Befehl' fehlschlägt ( ||), ruft er eine neue Instanz von cmd auf, die die Batchdatei selbst aufruft ( /v (on)um die verzögerte Erweiterung zu aktivieren und /qdas Echo auszuschalten). Dann !!wird zu nichts expandiert, da es keine aufgerufene Variable gibt <NULL>. Der Rest Ihres Skripts wird dann ausgeführt. Danach kehrt es zur ursprünglichen Instanz von cmd zurück, und ( &&) wird mit der /bBedingung beendet, dass das Fenster geöffnet bleibt (beim Beenden wird das Skript nicht im Kontext der ersten cmd-Instanz mit Echo weiter ausgeführt ein und verzögerte Erweiterung aus).

unclemeat
quelle
Aus diesem cmd /q /v on /c <filename>Grund sollte das Ausführen von Batch-Dateien mit nur 2 Bytes zählen, da es sich um zwei "Flags" handelt, die den Perl-Flags ähneln und -pInur 2 zusätzliche Bytes umfassen.
Artyer
1

Wiederholte Zeichenfolgen

Setzen Sie sich wiederholende Codeblöcke in Variablen, wobei die Anzahl der zum Setzen der Variablen verwendeten Bytes + die Anzahl der zur Ausgabe der Variablen verwendeten Bytes kleiner ist als die Anzahl der Bytes, um den Code nur direkt aufzurufen.

Ein Beispiel finden Sie unter: Zeichnen Sie die Kombinationen, die 100 ergeben

Sie sparen 1 Byte pro Verwendung des Befehls set, wenn Sie eine Variable (benannt mit einem Zeichen, wie "s") erstellen, die enthält set<space>. Dies erzeugt nur dann einen Wert, wenn Sie den Befehl set mehr als 12 Mal verwenden. (Beachten Sie, dass am Ende der Zeichenfolge ein Zeichen steht 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

Das obige ist 1 Byte kürzer als ..

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

Dies ist wahrscheinlich ein ziemlich schlechtes Beispiel - aber es bringt den Punkt auf den Punkt.

unclemeat
quelle
1

Beginn einer Zeichenfolge

Die Notation %var:~start,end%extrahiert einen Teil der Variablen var. Wenn dies jedoch der Fall startist 0, können Sie es ganz weglassen. Wir wissen bereits, dass Sie weglassen können, ,endwenn Sie den Rest der Zeichenfolge verwenden möchten. Dies ist %var:~%ein fast unbrauchbares Synonym für %var%, mit der Ausnahme, dass die Zeichenfolge zurückgegeben wird, ~wenn sie %var%leer ist. (Vielleicht könnten Sie es in einem Test verwenden if %var:~%==~:?)

Neil
quelle
Ich mag deinen letzten Satz, der uns daran erinnert, dass dies einige Zitate erspart :) +1 dafür.
Stevefestl
1

Verkürzende IF EQUAussagen

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

Verwenden ==statt equ spart 3 Bytes.


Verkürzung von Anführungszeichen in IFAnweisungen

Dies ist ein traditioneller sogenannter "sicherer" ifVergleich.

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

Gehen Sie folgendermaßen vor, um diese Anweisung zu verkürzen, wenn die Eingabe nur alphanumerisch / leer sein kann :

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

Es werden insgesamt 2 Bytes gespeichert.


Herausforderungen, die Leistung erfordern

Wenn die Frage so aussagt:

Gibt mindestens 1 sichtbares Zeichen aus.

dann könntest du das einfach machen:

cd

Das cdzeigt das aktuelle Verzeichnis an STDOUT.


GOTOein Etikett

Hier sind einige Methoden zum gotoErstellen einer Bezeichnung, die in absteigender Reihenfolge der Bytes angeordnet sind.

goto :l
goto l
goto:l

Die obige Methode spart 1 Byte.

stevefestl
quelle
1
Alternativ können Sie auch goto:ldas gleiche 1 Byte speichern und den zusätzlichen Bonus erhalten, dass Ihr Doppelpunkt intakt bleibt
Matheus Avellar,
@ MatheusAvellar: Ich habe den Inhalt entsprechend Ihrem Kommentar hinzugefügt
stevefestl
1

Leerzeichen zwischen Befehl und Parametern mit Schrägstrichen weglassen

Entschuldigung für den nicht informativen Titel. Ich versuche zu verstehen, dass Sie bei einigen (nicht allen) Windows-Befehlen das Leerzeichen zwischen dem Befehls- / Programmnamen und dem Parameter weglassen können, solange dieser Parameter mit einem Schrägstrich beginnt. Beispielsweise:

for /f %%G in ...

wird

for/f %%G in ...

-1 Byte!

Piping-Ausgabe anstelle von ERRORLEVEL

Die Verwendung von ERRORLEVEL zum Ermitteln, ob ein Befehl ordnungsgemäß ausgeführt wurde, ist nicht die kürzeste oder eleganteste Methode. Stattdessen können Sie die Ausgabe weiterleiten. Dies funktioniert wie folgt (denken Sie daran, dass jeder Befehl nach dem &&Operator nur ausgeführt wird, wenn der Befehl vor dem &&ohne Fehler ausgeführt wurde. Ein Befehl nach dem ||Operator wird dagegen nur ausgeführt, wenn der Befehl vor dem Operator NICHT ordnungsgemäß ausgeführt wurde. Mein Beispiel ist :

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

Dies könnte ersetzt werden durch:

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

-26 Bytes, wow! Beachten Sie, dass dies mit Befehlen wie nicht funktioniertchoice , bei denen der ERRORLEVEL einen bestimmten Wert hat, der bestimmten Eingaben entspricht.

Grüße,
Gabe

Gabriel Mills
quelle
1

Klammern effektiv nutzen

Hallo nochmal,

Es tut mir leid, eine zweite Antwort zu schreiben, aber ich hatte das Gefühl, diese verdient zu haben. Ich habe festgestellt, dass Benutzer häufig eine der folgenden Methoden verwenden, um die Befehlsausgabe anzuzeigen, ohne diese lästige C:\Windows\System32>echo fooZeile vor jedem Befehl anzuzeigen .
Die erste Methode (mit echo off):

@echo off
echo foo
echo bar
echo foobar
echo barfoo

Die zweite Methode:

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

Keine dieser Methoden ist jedoch so kurz wie die folgenden:

@(echo foo
echo bar
echo foobar
echo barfoo)

Ziemlich praktisch, oder? Mit dieser Funktion können mehrere Ausgabezeilen auf einfache Weise an eine Datei oder ein Gerät weitergeleitet werden. Zum Beispiel dieser lange Code:

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

wird deutlich kürzer:

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

Vielen Dank, dass Sie diese ziemlich lange Antwort gelesen haben, und ich hoffe, das hilft Ihnen. Grüße,
Gabe

Gabriel Mills
quelle
Das Posten mehrerer Antworten auf Fragen mit Tipps ist nicht schlecht.
Erik der Outgolfer