Файл исполняемого скрипта, работающий в POSIX и Windows


16

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

> .\foo.cmd
Hello Windows! 

... но также может быть вызвана неизменным из типичного POSIX-совместимой (Linux / OSX) приглашение оболочки ( bash, tcshили zsh), чтобы выполнить произвольный POSIX-специфический код:

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

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

Я знаю, что это возможно, но с помощью cruft (то есть в Windows одна или две строки мусора / сообщения об ошибке выводятся в stderr или stdout перед «Hello Windows!»).

Критерием выигрыша является минимизация (первого) количества линий крафта и (второго) количества символов крафта.

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

Вторичным критерием является простота / элегантность решения внутри foo.cmd: если «инфраструктура» определяется как любой символ, непосредственно не участвующий в произвольном коде полезной нагрузки, то сначала минимизируйте количество строк, содержащих символы инфраструктуры, а затем - общее количество инфраструктуры. персонажи.

Дополнительные похвалы, если POSIX-часть будет работать, несмотря на то, что в файле есть окончания CRLF! (Не уверен, что последняя часть даже возможна.)

Мое существующее решение, которое я опубликую здесь, как только у других появится возможность, использует 6 строк кода инфраструктуры (52 символа без учета новых строк). Он выдает 5 строк Cruft, две из которых являются пустыми, и все они происходят в Windows (30 символов, исключая символы новой строки и исключая текущую строку каталога / приглашения, которая появляется в двух из этих строк).


должен быть сценарий оболочки / пакет, да?
кот

1
Кто-нибудь знает о пробной онлайн-среде для DOS?
Цифровая травма

1
Я нашел этот, но он не позволяет мне вводить символы ":", "\", "{" или "}": - /
Цифровая травма

@DigitalTrauma Существует Wine (который вы должны были установить, если вы этого не сделаете, потому что это удобно)
кошка

1
@ Cat спасибо - мой ответ, кажется, работает под вином.
Цифровая травма

Ответы:


15

0 линий, 0 символов, 2 инфра. линии, 21 ниже chars, CRLF ок

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

Убрал другое решение.

Использование 17 символов exit /bиз ответа Digital Trauma:

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

Сильный соперник! В частности, вторая версия (по критерию простоты / элегантности гораздо приятнее не разбирать линии полезной нагрузки так, как это делает первая версия). Это работает для меня на Windows и OSX. Первоначально я получал одну строчку изречений, : command not foundкогда в полезную нагрузку posix закрадывалась пустая строка, но я наконец понял, что речь идет не о :первой строке, а о том, что CRLF не защищены #. Для меня стало новостью, что #!линия не нужна - это было причиной двух строк Windows Cruft в моей предыдущей версии.
Jez

Первую версию сложно оценить - поскольку она предположительно добавляет символы : ` >&3` \ в каждую строку полезной нагрузки, я думаю, вы могли бы сказать, что ее инфраструктурная стоимость произвольно высока.
Jez

@jez Вы рассчитываете числовой балл за ответы? Если это так, то вам нужно прояснить вопрос о том, как это сделать.
Цифровая травма

Я новичок в codegolf, так ТВН я думал , что я ожидал , чтобы выиграть ответы объективно как - то. Тем не менее, я думаю, что вопрос проясняет: во-первых, количество линий разметки; разорвать связи по этому количеству персонажей; затем по количеству линий инфраструктуры, затем по числу символов инфраструктуры. Я не ожидал решений, которые изменяют линии полезной нагрузки, как первое решение Джимми. Я немного изменю вопрос, чтобы прояснить, что это нежелательно (извините за это небольшое изменение в стойке ворот, но я не думаю, что это пока влияет на его второе решение или любую вашу версию)
jez

Похоже, наши ответы сходятся ;-) У вас есть преимущество в оценке, хотя с использованием 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 и 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:~$ 

Чтобы создать это точно (с 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 Version 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

Обратите внимание, что вы можете ввести символ 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 Cruft: 5 строк (из которых две пустые) / 30 символов
  • OSX Cruft: 0
  • Инфраструктура: 6 строк / 52 символа
  • Совместимость с CRLF: только в том случае, если названный в #!строке интерпретатор не заботится (поэтому для стандартных интерпретаторов, таких как shи друзья, он не работает)

В POSIX сценарий всегда начинается с #!, что означает, что ваш единственный ответ на данный момент является действительным сценарием в системе POSIX. Конечно, некоторые другие могут работать, если - но только если они запускаются из оболочки с обходным решением для неисправных сценариев.
kasperd

Хорошо знать! Я предполагаю, что я нечетко по строгим критериям для соответствия POSIX. Моя настоящая цель - иметь файлы сценариев, которые работают «из коробки» на «большинстве» современных настольных систем, что бы это ни значило - Windows 7/8/10, Ubuntu, OSX ... Насколько универсален обходной путь для сценариев без бейфинга, Я думаю? Во всяком случае, я не собираюсь присваивать очки себе :-)
Jez

Я не заметил, что и ответ, и вопрос были написаны одним и тем же человеком. Я думаю, что все оболочки, с #!которыми я работал, имеют обходной путь для пропущенной строки, но они будут использовать разные оболочки для интерпретации сценария. Это означает, что «скрипт», который не начинается с, #!должен быть действительным не только в одной оболочке, но и в каждой оболочке, которую он мог бы интерпретировать. Но что еще хуже, он работает только при запуске из другой оболочки. Такой скрипт может работать из командной строки, но не в контексте, где вы, наконец, намереваетесь его использовать.
kasperd

Спасибо, это очень познавательный материал и именно то, что я надеялся выучить, начав этот вызов. В тех случаях, когда это будет (или может) иметь значение, #!строку в моем отредактированном ответе (1 строка инфраструктуры с 21 символом) можно объединить с ответом кого-либо еще при стоимости обработки только для Windows 2 строки (из которых одна пустая) или 23 символа
Jez

2

Резюме / обобщение ответов и обсуждение

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

Некоторое несоответствие, связанное с Windows, неизбежно, если в вашей системе POSIX вам нужно запустить скрипт со #!строкой. Если у вас нет другого выбора, кроме как сделать это, то эта строка:

#!/bin/sh # 2>NUL

это, вероятно, лучшее, что он может получить. Это приводит к выводу одной пустой строки и одной строки Cruft на консоль 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)но фигурные скобки имеют синтаксис bash-only):

:<<@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.