POSIXおよびWindowsで実行される実行可能スクリプトファイル


16

課題:任意のWindows固有のコードを実行するために、(PowerShellではなく管理者モードではなく)foo.cmdWindows cmd.exeプロンプトから呼び出すことができる単一のスクリプトファイルを記述します...

> .\foo.cmd
Hello Windows! 

...だけでなく、一般的なPOSIX準拠する(Linux / OSX)から変更されていない呼び出される(プロンプトシェルbashtcshまたはzsh任意POSIX固有のコードを実行するために、):

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

...サードパーティのインタプリタ/ツールのインストールまたは作成を必要としません。

私はこれが可能であることを知っていますが、クラフとは(つまり、Windowsでは、「Hello Windows!」の前にstderrまたはstdoutに1行または2行のゴミ/エラーメッセージが出力されます)。

勝利の基準は、(最初​​の)cruft行の数の最小化、および(2番目の)cruft文字の数の最小化です。

Cruftは、(任意の)ペイロードコードによって生成されないコンソール出力(stdoutまたはstderr)として定義できます。空白行は行数にカウントされます。改行は文字数にはカウントされません。両方のプラットフォームでクラフトスコアを合計する必要があります。clsそのようなメカニズムを無視して、残骸を一掃しますが、以前の端末出力も消去します。Windowsが@echo offまだ有効になっていないためにコマンドをエコーする場合は、現在のディレクトリとプロンプトの印刷に費やす文字を除外しましょう。

2番目の基準は、内部のソリューションのシンプルさ/優雅さfoo.cmdです。「インフラストラクチャ」が任意のペイロードコードに直接関与しない文字として定義されている場合、最初にインフラストラクチャ文字を含む行の数を最小化し、次にインフラストラクチャの総数を最小化します文字。

ファイルにCRLFの行末があるにもかかわらずPOSIX部分が機能する場合の追加の称賛!(最後の部分が可能かどうかわからない。)

私の既存のソリューションは、他の人がチャンスを得たらここに投稿しますが、6行のインフラストラクチャコード(改行を除く52文字)を使用します。5行のクラフを生成し、そのうちの2行は空白で、すべてがWindowsで発生します(改行を除き、これらの行の2つに現れる現在のディレクトリ/プロンプト文字列を除く30文字)。


持っている yaは、シェル/バッチスクリプトであることを?

1
誰もがDOSのオンライン試用環境を知っていますか?
デジタル外傷

1
これを見つけましたが、「:」、「\」、「{」、または「}」の文字を入力できません:-/
Digital Trauma

@DigitalTrauma Wineがあります(インストールしない場合は便利ですので、インストールする必要があります)
cat

1
@cat thanks-私の答えは今、ワインの下でうまくいくようです。
デジタル外傷

回答:


15

不要な行は0、不要な文字は0、インフラは2です。行、21インフラ。文字、CRLF OK

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

他のソリューションを削除しました。

exit /bDigital Traumaの回答から使用した17文字:

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

強力な候補!特に2番目のバージョン(シンプル/エレガンスの基準では、最初のバージョンのようにペイロード行を変更する必要がない方がはるかに優れています)。これはWindowsとOSXで実行されます。最初に: command not found、空行がposixペイロードに忍び込むたびに、1行のコメントを受け取りましたが、最終的:には最初の行ではなく、CRLFが保護されていないことがわかりました##!以前のバージョンのWindows cruftの2つの行を担当していた行が必要ないことは、私にとってはニュースでした。
ジェズ

最初のバージョンはスコア付けが困難です。おそらく、ペイロードのすべての行に文字: ` >&3` \ が追加されるため、インフラストラクチャコストはarbitrarily意的に高いと言えるでしょう。
ジェズ

@jez回答の数値スコアを計算していますか?もしそうなら、あなたはそれをどのように行うかという質問でそれをもっと明確にする必要があります。
デジタル外傷

私はcodegolfが初めてなので、TBHは何らかの形で客観的に回答を記録することが期待されていると思いました。それにもかかわらず、私は質問がそれを明らかにすると思う:最初に、重要な行の数。残酷なキャラクターの数によってそれを壊す。インフラストラクチャの行数、インフラストラクチャの文字数。ジミーの最初のソリューションのように、ペイロード行を変更するソリューションを期待していませんでした。私はそれはそれは望ましくないです(すみません、そのわずかなゴールポストシフトのためのが、私はそれがこれまでの彼の第二の溶液またはあなたのすべてのバージョンに影響を与えないと思う)をクリアにするために少し疑問を変更します
ジェズ

私たちの答えは収束しているように見えます;-)あなたはヒアドックの使用法で得点に優位を持っています。最終は#必要ですか?
デジタル外傷

4

0残骸+ 4インフラライン+ 32インフラチャー。LF&CRLF OK。

これは、私がこのブログで見つけたものに基づいており、Amigaビットおよびその他の不要な行は削除されています。\これはCRLFとLFの両方で機能するように、DOSの行を行継続を使用する代わりにコメント付き引用符で隠しました。

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

DOS CRLFまたは* nix LFの行末で、Ubuntu、OSX、およびワインで動作します。

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、Darwin Kernelバージョン13.3.0、GNU bashバージョン3.2.51)では、以下で実行できませ ./dosix.cmd: line 13: syntax error: unexpected end of file ん。
jez

@jezは、UTF-8でエンコードされたファイルを保存し、Windowsの行末を保持していることを確認してください!

ああ、それは私が無意識のうちにWindowsの行末を持ち、最初のバージョンを使用していたために起こっていました。
ジェズ

挿入(またはCv)、入力(またはCm)によってBashにCR文字を入力できることに注意してください。
jimmy23013

@jezしたがって、これは0 cruft行+ 4インフラストラクチャ行+ 32インフラストラクチャ文字としてスコア付けされます。これらの数値を有意義な方法で組み合わせて、比較のために単一のスコアを作成する必要がありますか?
デジタル外傷

2

既に打ち負かされているので、使用していたソリューションを既に投稿します。Digital Traumaと同じブログエントリを読んだに違いないと思う私の同僚の厚意によるものです。

#!/bin/sh # >NUL 2>&1
echo \
@goto c \
>/dev/null
echo "Hello Posix!"
exit
:c
@echo Hello Windows!
  • Windows cruft:5行(うち2行は空白)/ 30文字
  • OSX cruft:0
  • インフラストラクチャ:6行/ 52文字
  • CRLF互換性:#!行で指定されたインタープリターが気にしない場合のみ(したがって、標準的なインタープリターshや友人の場合、失敗します)

POSIXでは、スクリプトは常にで始まります#!。これは、これまでのところ、POSIXシステムで有効なスクリプトである唯一の答えであることを意味します。確かに他のいくつかが実行される可能性があります-しかし、それらが障害のあるスクリプトの回避策でシェルから起動された場合のみです。
カスペルド

知っておきたい!POSIX準拠の厳密な基準については曖昧だと思います。私の本当の目標は、Windows 7/8/10、Ubuntu、OSXなど、「ほとんどの」最新のデスクトップシステムで「そのまま」動作するスクリプトファイルを作成することです。シバンレススクリプトの回避策はどれほど普遍的か、私は疑問に思う?とにかく、私は自分にポイントを授与するつもりはありません:
jez

私は、答えと質問の両方が同じ人によって書かれたことに気付いていませんでした。私が使用したすべてのシェルには#!行がない場合の回避策がありますが、スクリプトの解釈に異なるシェルを使用します。つまり、最初の#!シェルではない「スクリプト」は、1つのシェルだけでなく、もっともらしい解釈が可能なすべてのシェルで有効でなければなりません。しかし、さらに悪いことに、別のシェルから起動した場合にのみ機能します。このようなスクリプトはコマンドラインからは機能しますが、最終的に使用する予定のコンテキストでは機能しません。
カスペルド

ありがとう、これは非常に教育的なものであり、まさにこの挑戦を始めることで私が学びたいと思っていた種類のものです。これが問題になる場合(または問題になる場合)に#!は、編集済みの回答(21文字のインフラストラクチャ行1行)の行を、Windows専用の2行(うち1行は空白)のコストで他の人の回答と組み合わせることができます。 23文字。
ジェズ

2

回答と議論の要約/統合

これは楽しかったし、たくさん学んだ。

POSIXシステムでスクリプトを#!行で開始する必要がある場合、Windows固有の問題は避けられません。これを行う以外に選択肢がない場合、次の行:

#!/bin/sh # 2>NUL

おそらく最高です。これにより、1行の空白行と1行のクラフがWindowsコンソールに出力されます。しかし、あなた#!行なしで逃げることができるかもしれません:ほとんどのシステムでは、通常のシェルインタープリターの1つがスクリプトを実行することになります(問題はどのインタープリターが普遍的に予測可能でないかです-それは依存しますが、必ずしもコマンドと同じシェルである必要はありません)。

トリッキーな最初の行を超えて、本当に独創的な無慈悲なソリューションがありました。jimmy23013による受賞作品は、2つの短いインフラストラクチャラインのみで構成:され、両方のプラットフォームで「サイレント」ラインを実装するためにキャラクターの二重の役割を利用しました(事実上のノーオペレーションshと友人として、そしてラベルとして内のマーカーcmd.exe):

:<<@exit/b

:: Arbitrary Windows code goes here

@exit/b
#
# Arbitrary POSIX code goes here 

CRLFの行末にもかかわらず、このようなスクリプトをPOSIXシステムで実行すること可能ですが、ほとんどのインタープリターに対してこれを行うには、POSIXセクションのすべての行(空白行も含む)をコメントまたはコメント文字で終了する必要があります。

最後に、すべての人の意見に基づいて私が開発したソリューションの2つのバリエーションがあります。それらは、CRLF互換性の欠如による損害を最小限に抑え、CRLF互換性をさらにスムーズにするという点で、ほとんどすべての世界で最も優れている可能性があります#!。2つの追加のインフラストラクチャラインが必要です。1つの(標準化された)行のみが予測不可能な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

最後の工夫として\r、行をシェルに渡す前に文字を削除することにより、これらの厄介な行末コメントを取り除き、CRLFの堅牢性を維持することができます。これにより、予測不可能なシェルに若干の信頼が置かれます({ 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

もちろん、このアプローチは標準入力をスクリプトにパイプする機能を犠牲にします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.