Получете местоположението на разгърнато приложение Matlab по време на изпълнение за Mac и Linux

Имам някои самостоятелни програми на Matlab, които по различни причини трябва да имат достъп до файлове в директорията, в която се намират (или за стартиране на друга програма, или за четене на някои XML файлове там). Имам следната функция, която работи за Windows:

function execDir = get_deployed_exec_dir()
% Returns the directory of the currently running executable, if deployed,
% an empty string if not deployed (or if unable to determine the directory)
execDir = '';
if isdeployed
    [status, execDir] = system('path');
    if status == 0
        execDir = char(regexpi(execDir, 'Path=(.*?);', 'tokens', 'once'));
    end
end

За да го накарам да работи за Linux и Mac, реших, че мога да заменя system('path') с system('echo $PATH') и да променя регулярния израз, за ​​да отговаря на синтаксиса на Unix, но за разлика от Windows, директорията на текущо изпълнявания изпълним файл не изглежда автоматично добавена в началото на променливата на пътя. Има ли начин в рамките на Matlab да получа директорията на текущо изпълнявания изпълним файл (знам, че има за скрипта, но изглежда, че не работи правилно при внедряване), или трябва да редактирам скрипта, който настройва MCR, преди да стартирам приложението да зададе променлива, която моят код може да чете с командата system?

За конкретика, някъде в компютъра на потребителя се намира папка EXECFOLDER със структура:

EXECFOLDER
| exec1
| exec2
| run_exec1.sh
| run_exec2.sh
| data.xml

Искам да разбера пътя до EXECFOLDER независимо от това къде потребителят изпълнява run_exec1.sh (скрипт, който настройва MCR и извиква exec1), така че exec1 да може да чете от data.xml и да изпълнява exec2.

Резюме на опитите:

  • system('echo $PATH'): изпълнимата директория не е на пътя в Mac и Linux
  • matlabroot: местоположение на MCR
  • pwd: текущата папка на потребителя, която може да се различава от местоположението на изпълнимия файл, когато се изпълнява с пълен път
  • dbstack: местоположение на неопакования .m файл
  • which: местоположение на неопакования .m файл
  • fileattrib: местоположение на неопакования .m файл

person ackrause    schedule 25.07.2013    source източник
comment
Не съм напълно наясно какво ви трябва. Може ли внедрено приложение на Matlab да използва matlabroot? И какво е състоянието на pwd, когато програмата се стартира? Разбира се, има *NIX команди which и whereis, но те изглеждат тежки.   -  person horchler    schedule 26.07.2013
comment
В разгърнато приложение matlabroot ви предоставя местоположението на използвания MCR. pwd ви дава местоположението, в което се намира потребителят в терминала (където е извикал приложението), но за нашата програма хората са склонни да навигират до мястото, където са техните данни и да извикват програмата, използвайки нейния пълен път, така че къде всъщност са изпълнимите файлове е различно от текущата директория на потребителя. Чудех се дали има начин в Matlab да получа тази информация, без да се налага да настройвате променлива на средата в Bash скрипта, който използвате за стартиране на програмата.   -  person ackrause    schedule 26.07.2013
comment
Не мога да тествам това, но мисля, че имам по-добра представа за това, което питате. По отношение на MCR, внедрените приложения работят като функции на M-файл по отношение на Matlab. В такъв случай можете ли да извикате stack = dbstack('-completenames') fullpath = stack.Name, за да получите пълния път на изпълняваната в момента програма? Други неща, които да опитате може да са which (може би с флаг '-all') или може би fileattrib.   -  person horchler    schedule 26.07.2013
comment
dbstack, which и fileattrib всички изглежда ми дават местоположението, където .m файловете са разопаковани за изпълнение на MCR, а не първоначалното им местоположение в изпълнимия файл. Започвам да мисля, че това може да е толкова добро, колкото можете да направите в самия код на Matlab поради начина, по който се изпълнява.   -  person ackrause    schedule 27.07.2013
comment
Тогава нямам идея. Можете да изпълните почти всяка *NIX команда чрез функцията system и unix, така че може да се наложи да намерите решение там (напр. which, whereis и може би дори някаква форма на ps). Задавали ли сте този въпрос в MatlabCentral? Изглежда като нещо, което човек трябва да може да получи.   -  person horchler    schedule 27.07.2013
comment
Има също lsof на OS X и някои други форми на UNIX и /proc/<PID>/ на Linux, които може да са полезни.   -  person horchler    schedule 27.07.2013
comment
Наистина бих могъл да използвам обратна връзка за съществуващите отговори, тъй като ми е трудно да разбера кой от тях заслужава наградата.   -  person Dennis Jaheruddin    schedule 20.01.2015


Отговори (4)


Функцията ctfroot прави ли това, от което се нуждаете?

ctfroot е команда от компилатора на MATLAB. От документацията:

root = ctfroot връща низ, който е името на папката, в която е разширен архивът за разгръщане за разгърнатото приложение.

Вероятно искате да използвате командата ctfroot само в рамките на блок if isdeployed.

Редактиране

Ако имате нужда от местоположението на изпълнимия файл, а не местоположението, до което е разширен, можете да използвате следната функция:

function currentDir = getcurrentdir
if isdeployed % Stand-alone mode.
    [status, result] = system('path');
    currentDir = char(regexpi(result, 'Path=(.*?);', 'tokens', 'once'));
else % MATLAB mode.
    currentDir = pwd;
end

Това работи, тъй като пътят до изпълнимия файл се добавя към променливата PATH като първи запис от изпълнимия файл по време на изпълнение.

Като алтернатива можете да създадете MEX файл, който ще изпълнява подобна работа. Вижте този MathWorks support отговор за повече подробности и за примерен MEX файл.

person Sam Roberts    schedule 15.01.2015
comment
Мястото, където е „разширен“, същото ли е като мястото, където се намира? И тъй като не мога да го тествам сам: някой смята ли този отговор за по-добър или по-лош от отговора на @janus? - person Dennis Jaheruddin; 19.01.2015
comment
@DennisJaheruddin добави повече информация, която може да отговори на въпроса ви по-директно. - person Sam Roberts; 19.01.2015
comment
Не мога да го проверя сам, но искате да кажете, че този проблем е разгледан? но за разлика от Windows, директорията на текущо изпълнявания изпълним файл не изглежда да се добавя автоматично в началото на променливата на пътя - person Dennis Jaheruddin; 19.01.2015
comment
Бих предпочел да съм по-сигурен, преди да присъдя наградата, но предполагам, че заслужавате съмнението! - person Dennis Jaheruddin; 21.01.2015
comment
Съжалявам, @DennisJaheruddin, вчера нямах време да отговоря на коментара ви. Опасявам се, че нямам удобен достъп до платформа, различна от Windows, за да тествам дали моето решение работи там (или решението getCurrentDir, или решението с MEX-файл). Възможно е отговорът на Янус да е за предпочитане на LInux/Mac, не знам. Благодаря за наградата, но ако искате да я преназначите, не се притеснявайте. - person Sam Roberts; 21.01.2015
comment
Вашето системно („път“) решение работи за мен за компилирано приложение за Windows, благодаря за помощта - person Guy Starbuck; 27.07.2017

Има ли напредък по въпроса?

Това, което трябва да направите (и за двете платформи) е да получите достъп до 0-ия аргумент, предаден от обвивката на изпълнимия файл. Един от начините да направите това може да бъде обвиването на извикването към изпълнимия файл в скриптове и изрично предаване на местоположението:

myapp.bat:

set scriptpath=%~d0%~p0
"%scriptpath%%~n0%.exe" --ExecutablePath="%scriptpath%" %*

Или, ако не искате CMD прозорецът да остане наоколо

myapp.bat:

set scriptpath=%~d0%~p0
start "%~n0" "%scriptpath%%~n0%.exe" --ExecutablePath="%scriptpath%" %*

Bash всъщност е по-труден (вижте този въпрос), но нещо подобно може да свърши работа:

myapp.sh

#!/bin/bash
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
"${SCRIPTPATH}/myapp.o" --ExecutablePath="${SCRIPTPATH}" $*
person Janus    schedule 29.11.2013
comment
Тъй като не мога да го тествам сам: някой смята ли този отговор за по-добър или по-лош от отговора на @SamRoberts? - person Dennis Jaheruddin; 19.01.2015

Може би имате нужда от:

curr_dir = strrep(which(mfilename('fullpath')),mfilename,'')

който ще ви предостави директорията на .m файла, който се изпълнява в момента.

person BerndGit    schedule 14.01.2015

Mac: За да получите местоположението на инсталиран изпълним файл MyDeployedApplication.app на Mac от самото внедрено приложение, опитайте следното:

if isdeployed && ismac
    NameOfDeployedApp = 'MyDeployedApplication'; % do not include the '.app' extension
    [~, result] = system(['top -n100 -l1 | grep ' NameOfDeployedApp ' | awk ''{print $1}''']);
    result=strtrim(result);
    [status, result] = system(['ps xuwww -p ' result ' | tail -n1 | awk ''{print $NF}''']);
    if status==0
        diridx=strfind(result,[NameOfDeployedApp '.app']);
        realpwd=result(1:diridx-2);
    else
        msgbox({'realpwd not set:',result})
    end
else
    realpwd = pwd;
end

Това решение използва терминалните команди „ps“, „grep“ и „top“, предполага, че потребителят има един екземпляр на MyDeployedApplication.app, който се изпълнява в момента, и е тествано на MAC OS Yosemite 10.10. 5 само с MATLAB Compiler 2015a.

Забележка: Докато pgrep работеше, за да върне PID на внедреното, текущо работещо приложение извън приложението (директно в терминала или в отворена сесия на MATLAB), той не върна нищо от приложението. Оттук и използването на top и grep.

Linux: За да получите пътя на инсталирания изпълним файл на Linux, променете синтаксиса на отговора на Сам в стил Linux:

[status, result] = system('echo $PATH');
realpwd = char(regexpi(result, '(.*?):', 'tokens', 'once'));        
person Marianne    schedule 11.07.2016
comment
Забележка: Технически не мога да отговоря на нерешения въпрос на @dennis-jaheruddin относно отговора на sam-roberts, така че ще го поставя тук засега: допълнителното решение в секцията за редактиране на Sam работи за Windows, но не работи за Mac, както е установил първоначалният питащ. Това е така, защото Mac не добавя изпълнимия път към променливата на пътя при стартиране на внедреното приложение. Но дори и да го направи, командата ще трябва да бъде 'echo $PATH', а не 'path' и анализът, който се случва след това, ще трябва да използва двоеточие вместо точка и запетая, тъй като Mac използва точка и запетая като разделител, като Linux. - person Marianne; 11.07.2016
comment
Скъпа Мариан, какво ще кажете за решение за Windows? - person FabioSpaghetti; 17.05.2020