Как человек страстно ждавший возможность запуска exe-файлов внутри WSL, я хочу поделиться опытом правильного использования новой фичи.
Bash on Windows я использую для всякой мелкой механизации — выкачать, распарсить, проанализировать. Взять 10-20 гигов логов и поколдовать над ними в поисках чего нибудь этакого. Взять 200 гигов исходных данных, сделать ВЖУХ и пульнуть пару мегов результатов в базу сайта. Вобщем, обычная бытовуха, как у всех. Разве нет?
Итак, мой опыт
Кейс номер один
Вот то ради чего именно я ждал возможность запуска exe-файлов на WSL.
Имеется некоторое количество веб-сайтов для разных программ, требуется проверить что все ссылки «download» ведут на актуальные версии.
Пропустив этап поиска ссылок и скачивания файлов перейдём к извлечению нужной информации.
Делаем это двумя путями.
Путь первый — обращение к WMIC
В CMD вызов данной информации выглядит вот так:
wmic datafile where name="c:\\Windows\\System32\\cmd.exe" GET /VALUE
/VALUE — что бы получить всю возможную информацию
В bash это выглядит вот так
cmd.exe /C "wmic datafile where name='c:\\\\Windows\\\\System32\\\\cmd.exe' GET /VALUE"
слэшей много и все нужные
Но мне то нужно не просто на экран вывести, а получить и обработать.
Поэтому, в PHP это выглядит вот так:
// имя файла
$file='c:\Windows\System32\cmd.exe';
// получение данных через WMI
$q="/mnt/c/Windows/System32/cmd.exe /C \"wmic datafile where name='".addslashes(addslashes($file))."' GET /VALUE\"";
$a=exec($q,$b);
$ini=implode("\n",$b);
/mnt/c/Windows/System32/cmd.exe — полный путь, что бы наверняка
$b — результат многострочный, поэтому получаем его в виде массива (в $a попадает лишь последняя строчка)
$ini — формат результата совместим с ini-файлом, грех этим не воспользоваться — превращаем полученный массив $b в текст для последующего преобразования с помощью parse_ini_string().
Путь второй — использование Scripting.FileSystemObject
Данной решение я нашёл здесь и немножко допилил.
В исходном варианте был вызов короткого списка с результатами, что меня не устроило
WScript.Echo(objFolder.GetDetailsOf(objItem,-1));
Я заменил эту строчку на цикл извлекающий ВСЕ возможные свойства файла
var folder=objShell.NameSpace(namespace);
for (var i=0; i<0xFFFF; i++)
{
fileinfo=folder.GetDetailsOf(null, i);
if (!fileinfo)
{
break;
}
WScript.Echo( fileinfo+" = "+objFolder.GetDetailsOf(objItem,i) );
}
формат вывода сделан совместимым с ini-файлом.
PHP код, вызывающий bat-файл, получился вот такой
$q1="/mnt/c/Windows/System32/cmd.exe /C \"C:\\test_exe\\test_exe.bat ".addslashes($file)."\"";
$a1=exec($q1,$b1);
$ini1=implode("\n",$b1);
$ini1=iconv("CP866","UTF-8", $ini1);
Почти так же как как в случае с WMI, только приходится перекодировать результат в юникод. ( CP866 — всплакнул )
Склеиваем полученные результаты в единый текст и парсим
$result_ini="[WMIC]\n".$ini."\n[FileSystemObject]\n".$ini1;
$result_arr = parse_ini_string($result_ini, true, INI_SCANNER_RAW);
print_r($result_arr);
Делаем разбиение на секции (второй параметр — true) и во избежании проблем включаем — INI_SCANNER_RAW
ВЖУХ и получаем массив всех возможных свойств файла с которым удобно работать.
~$ cd /mnt/c/test_exe/
/mnt/c/test_exe$ php test_exe.php
Array
(
[WMIC] => Array
(
[AccessMask] => 1179817
[Archive] => TRUE
[Caption] => c:\windows\system32\cmd.exe
[Compressed] => FALSE
[CompressionMethod] =>
[CreationClassName] => CIM_LogicalFile
[CreationDate] => 20170318235750.921718+180
[CSCreationClassName] => Win32_ComputerSystem
[CSName] =>
[Description] => c:\windows\system32\cmd.exe
[Drive] => c:
[EightDotThreeFileName] => c:\windows\system32\cmd.exe
[Encrypted] => FALSE
[EncryptionMethod] =>
[Extension] => exe
[FileName] => cmd
[FileSize] => 271872
[FileType] => Application
[FSCreationClassName] => Win32_FileSystem
[FSName] => NTFS
[Hidden] => FALSE
[InstallDate] => 20170318235750.921718+180
[InUseCount] =>
[LastAccessed] => 20170318235750.921718+180
[LastModified] => 20170318235750.921718+180
[Manufacturer] => Microsoft Corporation
[Name] => c:\windows\system32\cmd.exe
[Path] => \windows\system32\
[Readable] => TRUE
[Status] => OK
[System] => FALSE
[Version] => 10.0.15063.0
[Writeable] => TRUE
)
[FileSystemObject] => Array
(
[Имя] => cmd.exe
[Размер] => 265 КБ
[Тип элемента] => Приложение
[Дата изменения] => 18.03.2017 23:57
[Дата создания] => 18.03.2017 23:57
[Дата доступа] => 18.03.2017 23:57
[Атрибуты] => A
[Автономность] =>
[Доступность] => Доступен автономно
[Распознанный тип] => Приложение
[Владелец] => TrustedInstaller
[Вид] => Программа
[Дата съемки] =>
[Исполнители] =>
[Альбом] =>
[Год] =>
[Жанр] =>
[Дирижер] =>
[Теги] =>
[Оценка] => Без оценки
[Авторы] =>
[Название] =>
[Тема] =>
[Категории] =>
[Комментарии] =>
[Авторские права] => c Microsoft Corporation. All rights reserved.
[№] =>
[Продолжительность] =>
[Скорость потока] =>
[С защитой] =>
[Камера, модель] =>
[Размеры] =>
[Камера, изготовитель] =>
[Организация] => Microsoft Corporation
[Описание файла] => Windows Command Processor
[Ключевые слова образцов] =>
[Имя программы] =>
[Длительность] =>
[В сети] =>
[Повторяется] =>
[Место] =>
[Адреса необязательных участников] =>
[Необязательные участники] =>
[Адрес организатора] =>
[Имя организатора] =>
[Время оповещения] =>
[Адреса обязательных участников] =>
[Обязательные участники] =>
[Ресурсы] =>
[Состояние собрания] =>
[Свободно/Занято] =>
[Общий размер] => 227 ГБ
[Учетная запись] =>
)
)
К чему был весь этот стрёмнокод? А вот к чему.
Как я уже упомянул ранее, на сайте майкрософта поведали, что теперь мы можем рисовать коров в PowerShell и запускать notepad.exe из баша.
А в обсуждении перевода этого майкрософтовского текста люди выясняют насколько там честный линукс и можно ли на него взгромоздить Докера.
Люди, вы не туда смотрите! Я в bash выполнил PHP-скрипт который через exec() запустил bat-файл в котором JScript создал ActiveXObject.
It's Kind Of Magic!
А ещё я могу из CMD сделать вот так:
C:\test_exe>bash -c "php test_exe.php"
А-а-а-а-а-а!
Кейс номер два
Обновление Windows 10 Creators Update я накатил 6 числа, а на прошлой недели был отвлечён от новой игрушки бухгалтерией. Бухгалтерия запросила оригиналы первички.
Эврика, подумал я и поставил консольную печаталку
Лезем в bash и просто запускаем программу
~$ 2Printer.exe -s "c:\2Printer\_input\*.*"
Результат — из принтера ползут листочки:
(данный скриншот — последующая имитация на виртуальном принтере, но на реальном HP тоже сработало)
В результате имеем:
- программа проявила интерактивность (триалка запросила нажать кнопочку)
- из башевского окошка полезла по своим виндовым путям
- взяла оттуда файлы с русскими названиями
- вызвала офисный редактор через COM-объекты
- отправила результат на принтер
То есть можно не только писать простейшие скриптики, но и использовать сложные программы.
Резюме
Я ещё не до конца осознал что ещё с этим можно делать, но эта штука может гораздо больше чем просто беседа с коровами и запуск LAMP.
Надо просто самому себе разрешить вырваться из дихотомиии «либо Linux, либо Windows» и начать скрещивать ежей и ужей в самых невероятных пропорциях и последовательностях.
Комментарии (47)
fuCtor
17.04.2017 07:18+2За счет изрядкой переработки консоли и доработки WSL в целом, работает такое.
Gorthauer87
17.04.2017 12:54+1Доктор Франкенштейн просто в восторге! Кстати, а сам гуй эмулятора терминала улучшили или он все так-же безнадежно отстал от terminal.app или же gnome-terminal.
fuCtor
17.04.2017 13:07Относительно названных не скажу, давно не пользоваляс ими, но субъективно стало комфортней работать. И цвета и отрисовки изменились в лучшую сторону. Выделение, вставка, изменения размеров уже и ранее были. Так что движутся в верном направлении и достаточно плотно работают с пользователями, быстро отвечают на issue в github, на форуме своем.
AlexMal
17.04.2017 15:58Вопрос по использованию tmux в windows: Как заставить работать горячие клавиши для создание окон?
ad1Dima
17.04.2017 11:48+2Вопрос от ламера: а почему первый вариант нельзя было сделать на PS, а не ждать баша?
ad1Dima
17.04.2017 11:56+2вот, к примеру, выгружают метаданные всех фоточек в папке в CSV https://blogs.technet.microsoft.com/heyscriptingguy/2014/02/06/use-powershell-to-find-metadata-from-photograph-files/
muxa_ru
17.04.2017 19:35Забыл поблагодарить за ссылку.
Посмотрю не является ли это вариантом одного из моих двух методов и, если нет, задействую и его.
muxa_ru
17.04.2017 13:09Потребность в массовой проверке версий программ появилась этой зимой, а тогда уже было известно что в весеннем обновлении будет возможность запуска exe-файлов из баша.
Поэтому я сперва сделал решение из двух файлов запускаемых по очереди и стал ждать нужного мне обновления обновления.ad1Dima
17.04.2017 14:18+1Эм вы как-то странно ответили на мой вопрос.
В чем пеимущество запуска на винде из баша пхпскрипта, который запускает cmd, который запускает виндовую тулзу перед скриптом в PS?muxa_ru
17.04.2017 14:55Я ответил на вопрос про ту часть где «не ждать», сорри.
В чем пеимущество запуска на винде из баша пхпскрипта, который запускает cmd, который запускает виндовую тулзу перед скриптом в PS?
В моём случае — в унифицированности.
Я для своих нужд делаю всякие разные скриптики для мелких задач.
Они все используют одни и теже общие папки, одни и теже общие базы, одни и те же общие функции.
Часть из них лезет на сервер, берёт исходные данные, что-то делает и возвращает на сервер результат.
И если они все «sh + php», то пусть и этот будет «sh + php». Чисто для простоты использования и обслуживания.
А иначе, если девять будут а BASH, а десятый в PowerShell, то есть вероятность что я на этого «десятого» забью и не буду использовать.
ad1Dima
17.04.2017 15:20+2ну, т.е, вы могли бы из баша PS скрипт запускать, а не городить цепочки?
muxa_ru
17.04.2017 19:33Если цель состоит в ручной проверке единственного файла — да
Но задача, как и написано выше, состоит в проверке множества файлов расположенных на разных сайтах.
В итоге:
— список проверяемых ссылок составляется php и хранится в mysql
— выкачивает файлы — wget
— результат обрабатывается php (нужно сравнить) и хранится в mysql + формируется отчёт
То есть, цепочка уже есть, просто часть её работы выполнял bat файл с wmic внутри. И он запускался отдельно.
Теперь этот функционал встроен прямо в php скрипт.
muxa_ru
17.04.2017 14:59Вобщем, если совсем коротко, то преимущество организационное, а не техническое
Gorthauer87
17.04.2017 12:50+1А вот это уже типичный EEE, сейчас вырастет куча скриптов, которые закладываются на особенности WSL и в особенности на виндовые бинарники, а потом вылезут сложности с их портированием на Linux.
То есть чисто практически фича конечно полезная, но если все начнут ей злоупотреблять, то получится франкенштейн, которого потом даже при помощи wine'а не запустишь нигде.
Впрочем, с другой стороны, теперь можно чисто видновые проблемы решать при помощи WSL.
Думаю, что открытие кода некоторых подсистем Windows сняло бы все такие сомнения и вопросы.
fuCtor
17.04.2017 13:24В большей степени интересно как этими возможностями воспользуются IDE строители, в принципе ничего не мешает организовать бесшовную интеграцию лишь поправив код запуска консольных команд.
kale
17.04.2017 13:58+1Зачем использовать абсолютные пути? Переменные окружения спасут вас от потенциальных проблем.
muxa_ru
17.04.2017 14:14Зачем использовать абсолютные пути?
Для подстраховки.
Когда вручную запускаю, то знаю из какогой папки, а когда из скрипта, то я лучше ВСЁ напишу в абсолютных путях, чем он сам хватанёт не оттуда
А так bash подцепляет переменные из Windows и при набранном trace по табу выводит варианты из обоих миров
~$ trace tracepath tracepath6 traceroute6 traceroute6.iputils tracerpt.exe
renskiy
17.04.2017 15:47насколько там честный линукс и можно ли на него взгромоздить Докера
Docker, установленный на винду «нативно», из баша не запустился. Хотя, возможно я не учел тот факт, что под виндой бинарник докера может называться docker.exe. Если так, то создание соответствующего alias в баше может помочь.
Zombieff
17.04.2017 19:54+1Тем, кто всё же считает эмулятор терминала в винде убогим, рекомендую попробовать ConEmu — хотя бы есть вкладки, профили, quake-режим с выдвигающейся по хоткею консоли, цвета получше настраиваются, да и вообще.
Лично я поставил себе дефолтной оболочкой в нём как раз bash — тогда под рукой всегда есть ssh, cURL, vim и всё остальное.Tallanvor
20.04.2017 13:27Спаситель!
После guake дико корёжило переключение на теминал под винде кликом/альт-табом.
А теперь — каеф :)
mayorovp
17.04.2017 20:10+1В чем смысл запуска
wmic.exe
черезcmd.exe
? Почему нельзя запустить его напрямую?muxa_ru
17.04.2017 20:39в этом смысла нет, это косяк :(
Увлёкся механическим переносом строчек из батника и забыл сделать вызов напрямую.
Увидел уже перед публикацией, но решил не исправлять. Типа если кто спросит, то отбрехаюсь мол «это специально иллюстрация того что cmd.exe нужно запускать с ключём /C „
Но нет, просто пробакланил. Сорри.
P.S. Если что, то он не wmic.exe, а WMIC.exe.
mikeus
19.04.2017 17:55+2Для описываемых применений можно использовать Cygwin — POSIX user-space в Windows с набором софта практически как в обычном Linux-дистрибутиве. Проекту уже «как сто лет в обед» и всякие заморочки со взаимодействием с Windows-миром пройдены и переварены, достаточно большое коммюнити пользователей, ведется при поддержке Redhat.
И да, там можно запустить X-сервер для GUI-программ или c целым десктопом как XFce/LXDE, или даже, например, из bash с помощью имеющегося в пакетах mingw-w64 скомпилировать нативную Windows-программу (не связанную с библиотекой Cygwin-POSIX), и, разумеется, запустить её, и например распарсить её консольный вывод с помощью unix-утилит или любого другого инструментария (типа PHP) в bash. :)
muxa_ru
19.04.2017 20:06+1Я думаю, что мои задачи мог бы решить и windows-версия php, но… ощущения не те
И цигвин как то пробовал — не встаёт.
То есть цигвин то у меня встаёт, а вот у меня на цигвин — нет.
muxa_ru
19.04.2017 21:31Не получается повторить второй пример, с печатью
$ 2Printer.exe -s "c:\2Printer\_input\*.*"
В wsl выполнилось, в cygwin висит и ничего не происходит.
Если без параметров, то работает
$ 2Printer.exe 2Printer, Version 5.3, - fCoder SIA 2017 -?, -help - display usage information -s - set source path for printing for example -s "c:\my folder\*.doc"
Там есть какие-нибудь особенности синтаксиса или ввода путей?mikeus
19.04.2017 22:07+1$ 2Printer.exe -s "c:\2Printer\_input\*.*"
Там есть какие-нибудь особенности синтаксиса или ввода путей?
Ну да.
Кстати в bash-шелле строка в двойных кавычках считается экранированной. И "*.*" не расширяется в список файлов. См. man bash раздел QUOTING. Не понятно вообще почему в WSL-bash это сработало.
Так что в Cygwin скорей всего надо так:
$ 2Printer.exe -s /cygdrive/c/2Printer/_input/*
Вот кстати пример того что майкрософт что-то намудрило с попыткой скрестить ужа и ежа.muxa_ru
19.04.2017 22:47У Вас на скриншоте тоже виндовые пути указаны.
Перебирал и юникосвые пути и двойные слэши. Не помогает.
Печалька
Есть идея — версия триальная и не срабатывает в месте запроса «выберите вариант»
Завтра попрошу у коллег серийник и попробую на лицензионной копии.
Спасибо за наводкуmikeus
19.04.2017 23:36+1Не, для 2Printer.exe я просто на автомате пути перебил не зная ничего об этой проге.
Сейчас скачал установил — это же виндовая прога и все что ей нужно просто дать строку во входном параметре не затронутую bash-шеллом, дальше она её сама разбирает.
Причина зависания что она хочет именно виндовую консоль и не работает в эмуляторе терминала mintty.exe. В директории установки Cygwin должен быть Cygwin.bat — он запустит bash в виндовой консоли. Из под неё все работает.
А в терминале mintty.exe только через запуск нового окна консоли cmd.exe удалось:
$ cmd /c start 2Printer.exe -verbose -pres 'c:\tmp$\pres.txt' -s 'c:\tmp$\tmp.txt'
mayorovp
20.04.2017 12:40+1В отличии от никсов, где звездочки раскрывает шелл, виндовым программам шаблоны имен файлов приходится раскрывать самим. Потому и работает.
Кстати, "намудрили" как раз создатели cygwin. У них программы по-разному получают свои аргументы себя ведут в зависимости от родительского процесса.
mikeus
20.04.2017 15:43+1Микс из Windows-мира и POSIX-окружения приводит к путаницам — кому где какие пути можно задавать в качестве аргументов или по каким путям будут искаться указанные в командной строке программы.
Пример:
— which (в Cygwin) находит fc как досовскую команду
$ which fc /cygdrive/c/Windows/system32/fc
— если в командной строке указать просто fc, то будет вызвана builtin команда bash, которая делает совсем другие вещи, а не досовсая fc.exe
— нужно вызывать указывая точно, что это именно fc.exe
$ fc.exe FC: Insufficient number of file specifications
— bash-шелл раскрывает шаблон и полученные имена передаются как аргументы досовской программы (т.е. здесь юниксовые пути для файлов из локальной директории прекрасно подходят досовской программе)
$ fc.exe *.log Comparing files make-1.log and MAKE-2.LOG FC: no differences encountered
— сама же Windows-программа звездочки в своих параметрах не раскрывает
$ fc.exe "*.log" FC: Insufficient number of file specifications
— и не понимает пути записанные через прямой слэш (не смотря на то, что в Windows как бы декларируется что для файловых путей прямые слэши допускаются вместо обратных)
$ fc.exe ./make-*.log FC: cannot open ./MAKE-1.LOG - No such file or folder $ fc.exe ./make-1.log ./make-2.log FC: cannot open ./MAKE-1.LOG - No such file or folder
— задаём полный прямой досовский путь к файлам экранируя строки параметров чтобы bash их никак не пытался затрагивать со своими фичами расширения параметров
$ fc.exe 'c:\cygwin.home\Mike\tmp\make-1.log' 'c:\cygwin.home\Mike\tmp\make-2.log' Comparing files C:\CYGWIN.HOME\MIKE\TMP\make-1.log and C:\CYGWIN.HOME\MIKE\TMP\MAKE-2.LOG FC: no differences encountered
— вот артефакт — программа не воспринимала ./make-1.log ./make-2.log, а микс параметров с разными способами задания путей проходит (и это не глюк Cygwin, точно так же она ведёт себя при запуске в родном cmd.exe
$ fc.exe 'c:\cygwin.home\Mike\tmp\make-1.log' ./make-2.log Comparing files C:\CYGWIN.HOME\MIKE\TMP\make-1.log and ./MAKE-2.LOG FC: no differences encountered
Я никогда не сталкивался в Cygwin с проблемами, связанными с тем, что какие-либо программы запущенные из bash по-разному получают свои аргументы в зависимости от того, из какого родительского процесса они были запущены (термнал mintty, досовская коносль cmd.exe, или в bash запущенном напрямую из проводника Windows).muxa_ru
20.04.2017 16:25Разница понятна, но я никогда не ленился писать полные имена файлов и абсолютные пути (где-то тут в комментариях даже вопрос был об этом) и проблему неоднозначности "fc" не чувствуют. Просто потому что неоднозначности для меня нет — одна программа называется fc, а другая fc.exe.
И с параметрами тоже самое. Для меня факт "запускаем любую программу с родными параметрами" является плюсом.
Да, невозможность скормить юниксовые пути виндовой программе иногда затрудняет выстраивание цепочек через пайп, но я могу запустить ЛЮБУЮ[1] консольную программу и она сработает.
То есть, у cygwin очень красиво с путями и параметрами, но на ограниченном количестве программ, а у wsl нужно ежам и ужам прописывать свои параметры, но зато набор инструментов не ограничен специальным репозиторием и специально скомпилированными экзешниками.
Мне нравится иметь именно все доступные программы и за эту возможность я готов платить необходимостью писать одним виндовые пути, а другим юниксовые.
Не спрашивайте зачем оно мне нужно. Пока ещё не знаю. Нужно свыкнуться с наличием таких возможностей. Нужно что бы в голове уложилось "ой, да запусти виндовую консольную утилиту и не парься". И тогда, в нужный момент, это будет использовано.
И в этом ключе, спасибо за идею о возможных проблемах связанных с разницей путей. Рано или поздно я с этим столкнусь и буду к этому готов. Если не технически, то, хотя бы, морально. :)
1 — совершенно некорректное обобщение малого количества экспериментов, но, как прогноз, прокатит.
mikeus
19.04.2017 21:47+1Cygwin был и остается прекрасной альтернативой почившему в бозе встроенному в Windows SFU/SUA с непонятными версиями программ, и которое в общем нацеливалось на непонятные задачи связанные со взаимодействием Windows-серверов с Unix-серверами, а не на предоставление привычного POSIX-окружения для пользователей Windows.
А теперь, когда макрософт полюбила линукс, WSL не то что бы конкурент Cygwin, а наверное его будущий убийца, если майкрософт захочет.
Valle
Они еще и копипасту в cmd сделали нормальную, и ресайз, и цвета и воообще удивляют.
VitP
Вы имеете в виду Ctrl+Insert / Shift+Insert? Несколько месяцев когда попробовал, вставка только ПКМ работала, что крайне неудобно было.
Valle
Ctrl-C/Ctrl-V или right click — все работает. Ctrl+Insert / Shift+Insert никогда до этого не пробовал, но тоже работает.
VitP
Странно, но у меня Shift+Insert никак не работает. А без этого шорт-ката совсем неудобно мышкой работать. Только из-за этого по прежнему остаюсь на Cygwin.
ad1Dima
Может они выключены по какой-то причине? https://www.cnet.com/how-to/new-windows-10-keyboard-shortcuts-for-the-command-prompt/
AlexMal
Я на ПК обновился, а на ноуте поставил систему с нуля. Так вот, на ПК Ctrl+Insert/Shift+Insert не работает, а на ноутбуке без проблем. Возможно где-то в настройках необходимо включить или переустановка системы.
Valle
Возможно вам еще не приехало обновление про которое речь в статье, the Creators Update. Его можно насильно поставить отсюда: https://www.microsoft.com/en-us/software-download/windows10
ad1Dima
Копирование по Ctrl-C точно было и в Anniversary, ну и собственно статья, на которую я сослался выше написана в августе 15, когда первая версия 10ки вышла.