在POSIX和Windows上运行的可执行脚本文件


16

挑战:编写一个脚本文件foo.cmd,可以从原始Windows cmd.exe提示符(不是PowerShell,不是以管理员模式)中调用该脚本文件,以执行任意Windows特定的代码...

> .\foo.cmd
Hello Windows! 

...也可被调用从符合POSIX标准典型(Linux的/ OSX)不变shell提示符(bashtcsh,或zsh),执行任意特定POSIX的代码:

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

...无需安装或创建第三方解释器/工具。

我知道这是可能的,但是使用了草率(即在Windows上,在“ Hello Windows!”之前,将一到两行垃圾/错误消息打印到stderr或stdout)。

获胜标准是最小化(第一)粗线的数量和(第二)细线字符的数量。

可以将Cruft定义为(任意)有效负载代码未产生的任何控制台输出(stdout或stderr)。空行计入行数。换行符不计入字符数。Cruft分数应在两个平台上求和。让我们忽略这样的机制cls,这些机制会清除残骸,但同时也会浪费掉先前的终端输出。如果Windows由于@echo off尚未旋转而回显您的命令,则排除在打印当前目录和提示时花费的字符。

第二个标准是内部解决方案的简单性/优雅性foo.cmd:如果将“基础结构”定义为任意有效载荷代码中不直接涉及的任何字符,则首先最小化包含基础结构字符的行数,其次将基础结构总数减少字符。

如果文件具有CRLF行尾,即使POSIX部分仍可以工作,请多加赞赏!(不确定最后一部分是否可能。)

我现有的解决方案(将在其他人有机会的情况下在此处发布)使用6行基础结构代码(52个字符,不包括换行符)。它产生5行粗体,其中2条为空白,所有这些都发生在Windows上(30个字符,不包括换行符,也不包括出现在其中两行的当前目录/提示字符串)。


必须是一个shell /批处理脚本,是吗?
2015年

1
有人知道DOS的在线试用环境吗?
Digital Trauma 2015年

1
我找到了这个,但它不允许我输入“:”,“ \”,“ {”或“}”字符:-/
Digital Trauma

@DigitalTrauma这里有Wine(如果没有的话,应该安装它,因为它很方便)
cat

1
@cat谢谢-我的回答似乎已经可以在葡萄酒下使用了。
Digital Trauma

Answers:


15

0个生产线,0个残炭,2个下层。第21行。字符,CRLF好的

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

删除了其他解决方案。

使用exit /bDigital Trauma的答案得出的17个字符:

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

强大的竞争者!特别是第二个版本(按照简单性/优雅性标准,不必像第一个版本那样修改有效负载行会更好。)这可以在Windows和OSX上为我运行。最初,我有一条粗俗的说法,: command not found每当空白行爬到posix有效负载中时,我最终就发现这不是:第一行,而是因为CRLF不受的保护#。对我来说,这是个新闻,#!不需要一行,这是我以前版本中Windows崩溃的两行。
jez

第一个版本是很难得分,因为它可能添加字符: ` >&3` \ 每一个有效载荷的线,我想你可以说,它的基础设施成本是任意高。
jez 2015年

@jez您正在计算答案的分数吗?如果是这样,您需要在如何做到这一点上更加清楚。
Digital Trauma 2015年

我是Codegolf的新手,所以TBH我以为我应该客观地为答案打分。尽管如此,我认为问题很明确:首先,生产线的数量;打破关系的关键人物; 然后是基础设施线路数,然后是基础设施字符数。我没想到像吉米的第一个解决方案那样会破坏有效负载线的解决方案。我将略微更改问题,以明确表明这是不可取的(很抱歉,门将发生轻微的转变,但到目前为止,我认为这不会影响他的第二个解决方案或您的任何版本)
jez 2015年

看来我们的答案正在收敛;-)尽管使用heredoc用法,您在得分方面还是有优势的。最后#必要吗?
Digital Trauma 2015年

4

得分0粗细+ 4个红外线行+ 32个红外线字符。LF&CRLF OK。

这是基于我在此博客中找到的内容,并去除了Amiga位和其他不必要的行。我将DOS行隐藏在带引号的引号中,而不是使用“ \行继续”,因此它可以与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:~$ 

要在* nix机器(包括OSX)上精确创建(使用CRLF),请将以下内容粘贴到终端上:

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

看起来不错! dosix也是个好名字。但是在我的Mac(OS 10.9.4,Darwin内核版本13.3.0,GNU bash版本3.2.51)上,它无法与以下命令一起运行: ./dosix.cmd: line 13: syntax error: unexpected end of file 知道为什么吗?
jez

@jez确保您保存使用UTF-8编码的文件并保留Windows行尾!

嗯,发生这种情况是因为我在不知不觉中拥有Windows行尾并且正在使用第一个版本的情况。
jez

请注意,您可以通过插入(或Cv),输入(或Cm)在Bash中输入CR字符。
jimmy23013 2015年

@jez因此,它的得分为0原始代码行+ 4基础设施行+ 32基础设施字符。是否应该以任何有意义的方式将这些数字组合起来以创建单个分数进行比较?
Digital Trauma 2015年

2

我已经发布了我一直在使用的解决方案,因为它已经被击败了。这是我的一位同事提供的,我认为他必须阅读过与Digital Trauma相同的博客条目。

#!/bin/sh # >NUL 2>&1
echo \
@goto c \
>/dev/null
echo "Hello Posix!"
exit
:c
@echo Hello Windows!
  • Windows Cruft:5行(其中两行为空白)/ 30个字符
  • OSX缓存:0
  • 基础设施:6行/ 52个字符
  • CRLF兼容性:仅当#!在线上指定的解释器不在乎时(因此对于像sh和朋友这样的标准解释器,它将失败)

在POSIX上,脚本始终以开头#!,这意味着迄今为止,您的唯一答案是成为POSIX系统上的有效脚本。确保其他某些程序可以在-的情况下运行,但前提是它们是从具有错误脚本的变通办法的Shell启动的。
kasperd

很高兴知道!我想我对POSIX合规性的严格标准很模糊。我的真正目标是让脚本文件可以在“大多数”现代台式机系统上“开箱即用”地工作,无论这意味着什么-Windows 7/8/10,Ubuntu,OSX ... shebangless脚本的解决方法有多普遍,我想知道?无论如何,我不会将积分奖励给自己:-)
jez

我没有注意到答案和问题都是同一个人写的。我认为我使用过的所有shell都有一种针对丢失#!行的解决方法,但是它们将使用不同的shell来解释脚本。这意味着一个不以“开始”的“脚本” #!不仅在一个shell中有效,而且在可能被解释的每个shell中都必须有效。但更糟糕的是,它仅在从另一个外壳启动时才起作用。这样的脚本可以从命令行运行,但不能在最终打算使用它的上下文中使用。
kasperd 2015年

谢谢,这是很有教育意义的东西,而正是我希望通过开始这一挑战来学习的东西。对于这将(或可能)很重要的情况,#!我编辑过的答案中的行(1个基础结构行含21个字符)可以与其他人的答案组合,而仅Windows的原始成本为2行(其中一个为空白)或23个字符。
jez

2

答案和讨论的总结/综合

这很有趣,我学到了很多东西。

如果在POSIX系统上需要用#!一行来启动脚本,则某些Windows特定的任务是不可避免的。如果您别无选择,请执行以下操作:

#!/bin/sh # 2>NUL

可能是最好的。这会导致在Windows控制台上输出一行空白行和一行废纸屑。但是,您可能无需离开就可以逃脱#!去做:在大多数系统上,通常的shell解释器之一将最终执行该脚本(问题是,并不确定哪个解释器是通用的-它取决于但取决于不一定与您用来调用命令的外壳完全相同)。

除了棘手的第一行之外,还有一些真正巧妙的无ft解决方案。jimmy23013的获奖作品仅由两条短的基础设施线组成,并利用角色的双重作用:在两个平台上实施了“沉默”线(作为事实上的无人sh和朋友,以及作为标签) )中的标记cmd.exe

:<<@exit/b

:: Arbitrary Windows code goes here

@exit/b
#
# Arbitrary POSIX code goes here 

可能使在POSIX系统这样的脚本运行甚至不顾CRLF行结束,而是为你必须结束大多数解释这样做的每一个注释或注释文字的POSIX段线(甚至是空行)。

最后,这是我根据每个人的意见开发的解决方案的两个变体。它们可能几乎是世界上最好的,因为它们可以最大程度地减少由于缺少而造成的损害#!,并使CRLF兼容性更加平滑。需要两条额外的基础设施线。不可预测的POSIX shell只需解释一行(标准化),而该行允许您为脚本的其余部分选择shell(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

最后,您可以删除那些讨厌的行尾注释,并通过\r在将行传递到外壳之前删除字符来保持CRLF鲁棒性。这使人们对不可预测的shell有了更多的信心(最好使用{ tr -d \\r|bash;}代替,(tr -d \\r|bash)但大括号仅用于bash语法):

:<<@GOTO:Z

@echo Hello Windows!

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

echo "Hello POSIX!"
ps

:Z

当然,这种方法牺牲了将标准输入输入到脚本的能力。

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.