批量打高尔夫球的技巧


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循环来收集输出:

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个字节,因此使用更长的脚本通常可以节省更多的字节。

命令通常不只是做显而易见的事情 -考虑命令的作用。例如; 如果您需要设置一个变量并回显另一个变量,而不是:

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

几个例子- 所有数的和 - 哥德巴赫的猜想

任何其他技巧都值得赞赏-如果我有其他想法,我会不断更新。


16
请将此答案的一部分作为答案而不是问题的一部分。
并不是查尔斯(Charles)

@Charles我相当确定我是如何做到的,这是“提示问题”的可接受格式。其他人可以使用自己的提示添加答案。
2014年

Answers:


4

专柜

每当您有一个变量将用作从其开始的计数器时,0可能要编写

set count=0
set/acount+=1

; 但是,您可以删除第一行,因为每当set/a与未设置的变量一起使用时,其值都假定为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个字节,更改echocd

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

因此您的代码可以保持可读性,而不会浪费字符。

可能会有例外,因为某些文本编辑器将换行符和卡式返回键结合在一起用于每个新行。


我将其包含在原始帖子中,因为在我使用的每个文本编辑器中,换行符都占两个字节。感谢您添加此说明。
2014年

2
Window的回程换行符是两个字符,许多文本编辑器会将其视为两个字符,但是当我第一次开始回答高尔夫问题时,剩下的评论之一说,在PPCG中,行尾始终被视为一个字符。
杰里·耶利米

2
Unix样式的换行符在CMD脚本中至少可以在Windows的最新版本中正常工作。
user2428118

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关闭echo)。然后!!将扩展为空,因为没有名为的变量<NULL>。然后,脚本的其余部分将运行。之后,它将返回到cmd的原始实例,并且(&&)退出并/b保持打开窗口的条件(退出是,因此它不会在第一个cmd实例的上下文中继续通过脚本运行,并带有echo并延迟扩展关闭)。


为此,使用来运行批处理文件cmd /q /v on /c <filename>应仅计为2个字节,因为它们是类似于Perl标志的两个“标志”,就像-pI它们仅计为2个额外字节一样。
Artyer

1

重复字符串

在变量中设置重复的代码块,其中用于设置变量的字节数+输出变量的字节数小于直接调用代码的字节数。

有关示例,请参见:绘制总计为100的组合

如果您创建一个包含的变量(以一个字符命名,例如“ s”),则每次使用set命令可节省1个字节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

cd显示当前目录STDOUT


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字节!

管道输出而不是使用ERRORLEVEL

使用ERRORLEVEL来确定命令是否正确运行不是最短或最优雅的方法。相反,您可以通过管道输出。它的工作方式如下(请记住,&&只有在&&运行之前的命令没有错误的情况下,操作员之后的任何命令才执行。||另一方面,只有在其之前的命令不能正常运行的情况下,操作员之后的任何命令才可以运行。 :

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

可以替换为:

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

-26字节,哇!请注意,这不适用于以下命令choice,其中ERRORLEVEL根据某些输入具有特殊的值。

问候,
加布


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

感谢您阅读这个冗长的答案,希望对您有所帮助。问候,
加布


发布提示问题的多个答案还不错。
Erik the Outgolfer
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.