Виконаний файл сценарію, який працює на POSIX та Windows


16

Завдання : написати єдиний файл сценарію, foo.cmdякий можна викликати у ванільній cmd.exeпідказці Windows (не PowerShell, не в режимі адміністратора), щоб виконати довільний код для Windows ...

> .\foo.cmd
Hello Windows! 

... але також виклик без змін із типової підказки bash, сумісної з POSIX (Linux / OSX) оболонки ( tcsh, або zsh), для виконання довільного коду, специфічного для POSIX:

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

... не вимагаючи встановлення чи створення сторонніх перекладачів / інструментів.

Я знаю, що це можливо, але з суворими (тобто в Windows, один або два рядки сміття / повідомлення про помилку друкуються до stderr або stdout перед "Привіт Windows!").

Критерієм виграшу є мінімізація (першої) кількості чітких ліній та (друга) кількості символів.

Cruft може бути визначений як будь-який консольний вихід (stdout або stderr), який не виробляється (довільним) кодом корисного навантаження. Порожні рядки зараховуються до числа ліній. Нові рядки не зараховуються до числа символів. Чіткі результати слід підсумовувати на обох платформах. Давайте ігноруємо подібні механізми, clsякі змітають крихту, але ціною також вимикання попереднього термінального виходу. Якщо Windows повторює ваші команди, оскільки ви ще не звернулися @echo off, давайте виключимо символи, які він витрачає, надрукуючи поточний каталог та підказку.

Вторинним критерієм є простота / вишуканість рішення всередині foo.cmd: якщо "інфраструктура" визначена як будь-який символ, який безпосередньо не бере участь у довільному коді корисного навантаження, то мінімізуйте спочатку кількість рядків, що містять символи інфраструктури, а друге загальну кількість інфраструктури символів.

Додаткові куди, якщо частина POSIX буде працювати, незважаючи на файл, що має рядки CRLF! (Я не впевнений, що остання частина навіть можлива.)

Моє існуюче рішення, яке я опублікую тут, коли інші зможуть, використовує 6 рядків інфраструктурного коду (52 символи без урахування нових рядків). Він створює 5 ліній суворості, дві з яких є порожніми, всі вони зустрічаються у Windows (30 символів, виключаючи нові рядки та виключаючи поточний рядок / рядок підказок, який з’являється у двох із цих рядків).


має бути сценарієм оболонки / партії, так?
кіт

1
Хтось знає про пробне середовище для DOS?
Цифрова травма

1
Я знайшов цього, але він не дозволяє мені вводити символи ":", "\", "{" або "}": - /
Digital Trauma

@DigitalTrauma Є вино (яке ви мали б встановити, якщо цього не потрібно, бо це зручно)
кіт

1
@cat спасибо - Моя відповідь, здається, працює під вином зараз.
Цифрова травма

Відповіді:


15

0 суворі лінії, 0 крихітні знаки, 2 інфрачервоні. лінії, 21 інфра. символів, CRLF ок

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

Інше рішення видалено.

17 символів за допомогою відповіді exit /bDigital Trauma:

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

Сильний претендент! Зокрема, другий варіант (за критерієм простоти / елегантності, набагато приємніше не змушувати обробляти лінії корисного навантаження так, як це робить перша версія). Це працює для мене в Windows та OSX. Спочатку я отримав один рядовий вислів : command not foundкожного разу, коли порожній рядок пробирався на корисну навантаження пози, але я нарешті з'ясував, що йдеться не про :перший рядок, а про те, що CRLF не захищені #. Мені стало новиною, що #!рядок не потрібен - це відповідало за дві лінії Windows Cruft у моїй попередній версії.
jez

Першу версію важко оцінити - оскільки, імовірно, вона додає символів : ` >&3` \ до кожного рядка корисної навантаження, я думаю, ви могли б сказати, що її інфраструктурна вартість довільно висока.
яд

@jez Ви розраховуєте числовий бал для відповідей? Якщо так, вам потрібно зробити це набагато зрозумілішим у питанні, як це зробити.
Цифрова травма

Я новачок у кодегольфі, тому TBH я думав, що від мене очікують як-небудь об'єктивно відповідати. Тим не менш, я думаю, що питання дає зрозуміти: по-перше, кількість чітких ліній; розірвати зв’язки на цьому за кількістю чітких символів; потім на кількість інфраструктурних ліній, потім на кількість символів інфраструктури. Я не очікував рішень, які сполучають лінії корисного навантаження, як перше рішення Джиммі. Я трохи зміню питання, щоб зрозуміти, що це небажано (вибачте за той незначний зсув воріт, але я не думаю, що це впливає на його друге рішення чи будь-яку Вашу версію досі)
я

Схоже, наші відповіді збігаються ;-) Ви маєте перевагу в забитті, хоча з використанням heredoc. Чи #необхідний фінал ?
Цифрова травма

4

Оцінка 0 чітких + 4 інфралінійних лінії + 32 інфрачервоних знаків. LF & CRLF ОК.

Це ґрунтується на тому, що я виявив у цьому блозі , з бітами Amiga та іншими непотрібними рядками. Я приховав рядки DOS в коментованих лапках замість того, щоб використовувати \рядок продовжує, так що це може працювати як з CRLF, так і з LF.

@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 (ОС 10.9.4, Darwin Kernel Version 13.3.0, GNU bash версія 3.2.51) він не працює з: ./dosix.cmd: line 13: syntax error: unexpected end of file Будь-яка ідея, чому?
ядра

@jez не забудьте зберегти файл, закодований UTF-8, і зберегти закінчення рядків Windows!
кіт

Ах, це сталося тому, що я несвідомо мав закінчення Windows-рядків і використовував першу версію.
jez

Зауважте, що ви можете ввести символ CR в Bash, вставивши (або Cv), введіть (або Cm).
jimmy23013

@jez Таким чином, це оцінюється як 0 чіткі лінії + 4 інфраструктурні лінії + 32 інфраструктурні символи. Чи слід поєднувати ці числа будь-яким змістом, щоб створити єдиний бал для порівняння?
Цифрова травма

2

Я вже розміщую рішення, яким я користувався, оскільки його вже побили. Це люб’язність мого колеги, яка, я думаю, повинна прочитати ту саму запис в блозі, що і Digital Trauma .

#!/bin/sh # >NUL 2>&1
echo \
@goto c \
>/dev/null
echo "Hello Posix!"
exit
:c
@echo Hello Windows!
  • Програма Windows: 5 рядків (з яких два порожні) / 30 символів
  • OSX: 0
  • Інфраструктура: 6 ліній / 52 символи
  • Сумісність із CRLF: лише якщо перекладач, названий у #!рядку, не переймається (тому для стандартних перекладачів, як shі друзів, це не вдається)

У POSIX сценарій завжди починається з #!, а це означає, що ваша єдина відповідь поки що є дійсним сценарієм у системі POSIX. Впевнені, що деякі з інших можуть працювати, якщо - але тільки якщо вони запущені з оболонки з вирішенням несправних сценаріїв.
kasperd

Добре знати! Я думаю, що я нечіткий за суворими критеріями дотримання POSIX. Моя реальна мета - створити файли сценаріїв, які працюють "поза коробкою" на "більшості" сучасних настільних систем, що б це не означало - Windows 7/8/10, Ubuntu, OSX ... Наскільки універсальним є рішення для сценаріїв shebangless, Цікаво? У всякому разі, я не збираюся присуджувати бали собі :-)
jez

Я не помічав, що і відповіді, і запитання писала одна і та ж людина. Я думаю, що всі оболонки, з якими я працював, мають вирішення для відсутнього #!рядка, але вони будуть використовувати різні оболонки для інтерпретації сценарію. Це означає, що "скрипт", який не починається з #!, повинен бути дійсним не лише в одній оболонці, а в кожній оболонці, яку вона правдоподібно може інтерпретувати. Але ще гірше, він працює лише тоді, коли запускається з іншої оболонки. Такий сценарій може працювати з командного рядка, але не в контексті, коли ви, нарешті, маєте намір його використовувати.
kasperd

Дякую, це дуже навчальний матеріал і саме те, про що я сподівався навчитися, починаючи цей виклик. У випадках, коли це буде (або може) мати значення, #!рядок у моїй відредагованій відповіді (1 інфраструктурна лінія з 21 символом) може поєднуватися з відповіддю будь-кого іншого за вартістю Windows, що становить лише два рядки (з яких один порожній) або 23 символи.
jez

2

Підсумок / узагальнення відповідей та обговорення

Це було весело, і я багато чому навчився.

Деякі специфічні для Windows файли неминучі, якщо у вашій системі POSIX вам потрібно запустити сценарій #!рядком. Якщо у вас немає альтернативи, як це зробити, то цей рядок:

#!/bin/sh # 2>NUL

це, мабуть, найкраще, що можна отримати. Це призводить до того, що на консолі Windows виводиться один порожній і один рядовий рядок. Однак, можливо , вам вдасться піти без #!лінії: у більшості систем один із звичайних інтерпретаторів оболонок закінчиться виконанням сценарію (проблема полягає в тому, що не повсюдно передбачувано, який інтерпретатор буде - це залежить, але буде не обов'язково бути ідентичним оболонці, яку ви використовуєте для виклику команди).

Поза тим хитромудрим першим рядком знайшлося кілька справді геніальних рішень без накипів. Виграшне подання jimmy23013 складалося лише з двох коротких інфраструктурних ліній і використовувало подвійну роль :персонажа, щоб реалізувати "безшумну" лінію на обох платформах (як де-факто не-оп в shі друзів, і як ярлик маркер cmd.exe):

:<<@exit/b

:: Arbitrary Windows code goes here

@exit/b
#
# Arbitrary POSIX code goes here 

Це є можливість зробити такий запустити скрипт на системах POSIX , навіть незважаючи на CRLF лінії закінчень, але зробити це для більшості перекладачів ви повинні закінчити кожну рядок вашого розділу POSIX (навіть порожні рядки) з коментарем або символом коментаря.

Нарешті, ось два варіанти рішення, яке я розробив, ґрунтуючись на вкладі всіх. Вони можуть бути чи не найкращими з усіх світів, оскільки вони мінімізують шкоду від нестачі #!та роблять сумісність CRLF ще більш гладкою. Потрібні дві додаткові інфраструктурні лінії. Тільки один (стандартизований) рядок повинен інтерпретуватися непередбачуваною оболонкою 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

Як остаточний твіст, ви можете позбутися від цих примхливих коментарів в кінці рядка і все ще зберегти CRLF-надійність, знімаючи \rсимволи перед тим, як передавати лінії до оболонки. Це надає трохи більшої віри в непередбачувану оболонку (було б непогано використовувати { tr -d \\r|bash;}замість, (tr -d \\r|bash)але фігурні дужки - це синтаксис лише для удару):

:<<@GOTO:Z

@echo Hello Windows!

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

echo "Hello POSIX!"
ps

:Z

Звичайно, такий підхід жертвує можливістю вводити stdin вхід у сценарій.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.