struggling with shell extension - macos

For a little bit of context, I am in the process of developing a serious game (~participatory simulation) with Netlogo using Hubnet. I'd like to dynamically link NetLogo with an external model so that players are able to:
1) run an external program (i.e. a model) from their hubnet client interface, specifying parameters as inputs, and
2) have access to simulation results (i.e. reading model outputs as external files).
I found that post:
https://groups.yahoo.com/neo/groups/netlogo-users/conversations/topics/8145
so I downloaded/installed the shell extensions with NetLogo 5.0.5 (Mac OsX 10.7.5) and started to play with it.
The good things, I am able to execute :
observer>shell:cd "path"
observer>shell:pwd
observer>shell:exec "ls" (and all commands that do not need input parameters such as shell:exec "cal", shell:exec "df"...).
Now the bad things...
1) I am consistently failing to launch any random application using these commands:
observer>shell:exec "Safari.app"
or
observer>shell:exec "Safari" (-->error)
My working directory is correct and Safari (or other apps I am trying to launch) is actually present but NetLogo returns the following error:
Extension exception: Cannot run program "Safari" (in directory "/Applications"): error=2, No such file or directory
error while observer running SHELL:EXEC
called by Command Center
2) I am also struggling to execute shell commands taking parameters (for instance, shell:exec "open" "parameter 1" "parameter 2" ...). I am unable to find the correct syntax so that NetLogo don't recognize the input parameters I'm trying to pass to the command.
I have a very limited experience in Unix and I am a relative beginner with NetLogo so I must be missing something somewhere.
If anybody could help me through this, that would be greatly appreciated!
Thanks a lot!
Clément

Is OS X, you have to use open to open .app files. As you noted, you have to separate arguments to the program. So
(shell:exec "open" "/Applications/Safari.app")
should do what you want.
Here's an example of an actual executable with multiple arguments:
(shell:exec "ls" "-l" "-t")
Finally, note that shell:exec is a reporter. It returns the output of the program as a string.

Related

Set Extended Attributes with AppleScript Objc

So I am looking for a way to set Mac specific extended attributes (specifically kMDItemWhereFroms) for a file (Image File, Jpg) using AppleScript or AppleScript-Objc.
There is a command line tool that will do this xattr -w kMDItemWhereFroms . The problem is that on the several machines that I have access to (10.12, 10.13, and 10.14) when you run this command as a do shell script from within an AppleScript it does not work, the metadata is not added to the file. If I set Script Debugger to debug mode, and go through the script step by step it will actually set the metadata, but since that is not the way I am running the script, it is more of an interesting fluke than anything else. I have tried running the command with both "com.apple.metadata:" included and not included with the shell script and that makes no difference.
I have tried running my script through SD, Script Editor and osascript, and they all fail to update the metadata. So I am thinking that this tool might be broken when called from an AppleScript.
I found setxattr but that looks like it only applies to C.
So my questions are
1. Is there a way to set the extended attributes of a file on MacOS using Aobjc? if not then
2. Is there a way to get setxattr to work with either version of AppleScript? Probably not so
3. Any ideas how I might be able to get the command line tool xattr -w kMDItemWhereFroms to work when using scripting?
This is more of an annoyance for me, I am just being stubborn with wanting the source of the file to show up in the "Where From" data in the Get Info window from the Finder. I already am setting some metadata for the file using exiftool. So it is more of an interesting problem for me, than a critical problem that I must try and solve now. Thanks!

Get the command line version of Maple

I am a mac user and I have maple installed on my computer. I can open maple like any other app. However I would like to work in terminal. I googled and
found that I can do that but I need to change some path. It was not well explained. I would really appreciate if someone can help me setting my path.
Thanks in advance.
You do not have to adjust the PATH environment variable. Doing so just makes calling the maple launch script for the Commandline Interface (aka CLI) a little easier.
Open a terminal window (xterm). Find the maple script of your Maple installation. Perhaps it will be located in some directory like /Library/Frameworks/Maple.framework/Versions/Current/bin/ say. You should be able to run that script in your terminal by running it using the full name, eg. /Library/Frameworks/Maple.framework/Versions/Current/bin/maple.
You could also alias the full name (explicit location) to some single short word.
That maple script sets everything it needs to run the Maple binaries, etc. You just have to run it (in a terminal).
Or you could make OSX launch a terminal window and call the maple script. Doesn't OSX have an automator for adding such things to the Dock? I forget the syntax but could it be something like,
open -a "/opt/X11/bin/xterm" --args "-e /Library/Frameworks/Maple.framework/Versions/Current/bin/maple"

How does the command prompt know where to find the requested compiler/interpreter?

When compiling/interpreting a program from the command prompt, how does the command prompt know where to find the requested compiler/interpreter?
Are these files stored in a specific place or something like that? I'm just about getting a hang of high-level programming, but I find it pretty hard to wrap my head around what happens under the hood.
There are two parts: Where to find the file just from it's filename, and what to do with it.
Where files (programs) are searched if just the name is entered:
Windows (CMD):
There is a variable %PATH% which has a list of ;-separated directories, eg. C:\Windows;C:\Windows\system32;C.\somethingelse. It is saved somewhere in the registry and can be set either in CMD itself or with a GUI somewhere in the OS configs.
Linux etc. (Bash and many more):
Similar, there is a variable $PATH which can be set at least in the shell and various config files, and the entries are separated by :, eg. /bin:/usr/bin/even/more. Priority is from left to right.
Additionally, some shells (eg. Bash) cache lookup results in their own implementation-specific way (depending on the configuration), because it's faster than having to check every directory in the path variable (at least if the searched program is in the last dir, everything has to be checked).
What to do with the file once it's found:
Windows:
In Windows, everything works with the filename suffix.
.exe and some others are native programs to start.
.bat is a shell script which is executed like it's manually written to the shell.
For every other suffix, it's configurable which program belongs to the suffix (stored in the registry, how to comfortably change it depends heavily on the used Windows version). Eg. you could say that .py belongs to your Python interpreter, the a file foo.py will start the interpreter. Btw., the same suffix-program configuration is usen when a file is double-clicked in the GUI file explorer, and of course program installers can add their entries too without the user having to do it.
Linux:
For Linux, the suffix is not as important. The first relevant thing is a binary (yes/no) flag x (x like executable) which exists for each file on the file system, just like file name, creation timestamp etc.etc.
If the x flag is set to yes:
Linux tries to detect what kind of program it is from the content. The difference between a native compiled binary program and a not-compiled script of some scripting language is pretty clear.
A native linux program is started by the kernel, like expected. Additional binary program types could be configured, eg. there is the Wine software which runs some Windows programs on Linux, and one could add a specification how Windows exe`s can be recognized inside and that they should be started with Wine.
For a text file with the x flag, the next step is to look at the first line, which should start with a '#!' (called shebang), followed by the path of the interpreter (eg. #!/bin/bash). Shell scripts (like the bat files on Windows) are realized this way, but it's not limited to classical shell scripts: Nothing prevents anyone from making a #!/bin/python script which Python content (of course, Python has to be installed for this to work).
If the x flag is set to no:
Shells like bash with usual configuration won't do anything, independent if it is a real program just without flag or a jpg image etc. For the GUI file managers:
Again, the content (and possibly the file name suffix too) is inspected to get the type, like jpg images, mp3 music, C++ source code etc.etc. (Linux knows pretty many types), and then the fitting program is looked up in a list configurable by the user and/or program installations (mime file type id <-> program).
...
Note that in the case of eg. Python scripts (which are just normal text files, not something for the kernel to work with), it can be done with and without x flag: With flag and a shebang line, or without flag and a matching mime list entry. In the "without flag" case, the shebang won't hurt if it is there, because Python (and many other scripting languages) consider it a comment because of the #.
Regarding interpreters on unix-based systems, lots of scripts start with a so-called shebang or hashbang (#! on the first line of the script) that tells what interpreter to invoke, see https://en.wikipedia.org/wiki/Shebang_%28Unix%29 .
When you enter something like some-program some-arguments, the shell will look through each directory listed in the environment variable $PATH for an executable file named some-program (on Windows it's %PATH% and some-program.exe).
This is not specific to compilers and interpreters - it happens whether some-program is gcc, python, firefox or notepad.

Execute Lua WINAPI code without displaying the shell

I created a simple Lua application using Alien for Lua. It works perfectly, except when you execute it, the Lua Shell shows as well. Is there a way to "hide" this shell, run it in background, turn it off, etc so that I simply see the message box?
Code:
require "luarocks.require"
require "alien"
local MessageBox = alien.User32.MessageBoxA
MessageBox:types{ret = "long", abi = "stdcall", "long", "string", "string", "long" }
MessageBox(0, "Hello World!", "My Window Title", 0x00000040)
Current Output:
Desired Output:
tl;dr
Rename your script to hello.wlua so that wlua.exe is used.
Details
While it is likely possible, if verbose, to locate and close the offending console window that Windows provided your process, it would be better if that console never appeared in the first place. If it does appear, then it is likely to flash on screen, and cause some users to be confused.
Subsystems
Windows has, since its earliest days, had the concept of a "subsystem" which each individual executable identifies with. Normal GUI applications are linked with /SUBSYSTEM:WINDOWS and get the full GUI treatment including the responsibility to create and display their own window(s) if and when needed.
Applications that expect to be run from a command line (or batch file) are linked with /SUBSYSTEM:CONSOLE, and as a result have standard file handles that are guaranteed to be open and are likely to be connected to some console window (or a pipe, or redirected to a file, but they do exist). That guarantee is strong enough that when a console program is started outside of a console (as when double-clicked from Exporer, or named in the Start|Run box) then the system automatically creates a console window for it, and binds the standard file handles to the new console.
There are other subsystems, but those two are the only important ones for normal users and developers.
lua.exe and wlua.exe
So why does this matter?
The stock lua.exe will be linked for the console, because that makes it possible to use interactively from a command prompt. However, it means that it will always be supplied with a console window even when you don't want one.
The Lua for Windows distribution (which from the pathname showing in your console's title bar it looks like you are using) includes a second copy named wlua.exe which only differs by being linked for the Windows subsystem. As a result, it only displays a window if the script explicitly creates one to display. Of course, it also means that it cannot be used interactively at the command prompt.
File types and associations
For convenience, you can associate the file type .wlua with wlua.exe, and name your GUI script with that file type. That will enable launching programs in the usual way without getting the extra consoles. Of course, when debugging them, you can always run them with lua.exe from a command prompt and take advantage of the existence of stdout and the utility of the print function.
On my PC (64-bit Win 7 Pro) I have the following associations, which look like they were created by the installation of Lua for Windows:
C:...>assoc .lua
.lua=Lua.Script
C:...>ftype lua.script
lua.script="C:\Program Files (x86)\Lua\5.1\lua.exe" "%1" %*
C:...>assoc .wlua
.wlua=wLua.Script
C:...>ftype Wlua.script
Wlua.script="C:\Program Files (x86)\Lua\5.1\wlua.exe" "%1" %*
Extra credit: PATHEXT
You could also add .lua to the PATHEXT environment variable to save typing the file type at the command prompt. I'm not configured that way presently, but have in the past done that. I found that the standard practice of naming both modules and scripts with the same file type made that less useful.
The PATHEXT environment variable lists the file types that will be searched for in the PATH when you name a program to run without specifying its file type. Documentation for this is rather hard to locate, as there does not appear to be a single MSDN page listing all the "official" environment variables and their usage. This chapter of a book about Windows NT has a nice description of the interaction of PATH and PATHEXT, and despite being subtly out of date in some respects, it is the clearest detailed explanation of how the command prompt operates that I've come across.
It clarifies that each folder in PATH is searched for each extension named in PATHEXT:
If the command name includes a file extension, the shell searches each directory for the exact file name specified by the command name. If the command name does not include a file extension, the shell adds the extensions listed in the PATHEXT environment variable, one by one, and searches the directory for that file name. Note that the shell tries all possible file extensions in a specific directory before moving on to search the next directory (if there is one).
It also documents how file types and associations interact with the command prompt. Despite its age, it is well worth the read.
Windows executables explicitly list the subsystem they run on. As the windows "lua.exe" is linked for the console subsystem, windows automagically creates a console window for it. Just relink "lua.exe" for gui subsystem, and you won't get to see the output any more unless you run it from a console window. BTW: Gui programs can programmatically create the console.
An alternative is closing the created console on start.
For that, you must first use SetStdHandle to redirect STDIN, STDOUT and STDERR (use a file open to device nul if you don't want it at all), and then call FreeConsole to finally dismiss your unloved console window. No sweat, you have "alien" set up already...
Programmatic solution (run the same script under wlua.exe if possible)
do
local i, j = 0, 0
repeat j = j + 1 until not arg[j]
repeat i = i - 1 until not arg[i-1]
local exe = arg[i]:lower()
-- check if the script is running under lua.exe
if exe:find('lua%.exe$') and not exe:find('wlua%.exe$') then
arg[i] = exe:gsub('lua%.exe$','w%0')
-- check if wlua.exe exists
if io.open(arg[i]) then
-- run the same script under wlua.exe
os.execute('"start "" "'..table.concat(arg,'" "',i,j-1)..'""')
-- exit right now to close console window
os.exit()
end
end
end
-- Your main program is here:
require "luarocks.require"
require "alien"
local MessageBox = alien.User32.MessageBoxA
MessageBox:types{ret = "long", abi = "stdcall", "long", "string", "string", "long" }
MessageBox(0, "Hello World!", "My Window Title", 0x00000040)
If you can use winapi module or have similar calls in Alien, you can find the handler of the console window and hide the window itself. The code would be similar to this:
require winapi
local pid = winapi.get_current_pid()
local wins = winapi.find_all_windows(function(w)
return w:get_process():get_pid() == pid
and w:get_class_name() == 'ConsoleWindowClass'
end)
for _,win in pairs(wins) do win:show_async(winapi.SW_HIDE) end
You'll need to check if this leave the MessageBox visible or not.

Bash: Getting standard program for file type

the background is a shell script to open the .m3u file of a web radio station. Therefore I want to know inside the script, what's the user's program to open such files. At the moment, he has to set the environment variable $PLAYER, but obviously that is not a good way to go.
Alternative: Is there a command that takes a filename and searches itself for an appropriate program to handle that file? Like file, e.g.,
open-file my_playlist.m3u
The script should be portable, it will run at least on Ubuntu, Debian and Windows/Cygwin machines.
Cheers,
This will have to be done differently on each platform. On Mac OS X the "open" command will do what you want.
In Linux it gets murky, since the desktop environment (GNOME or KDE) keeps its own list of applications to run for each file type.
There are two files you can look for in Ubuntu / GNOME that hold this info:
~/.local/share/applications/defaults.list and
~/.local/share/applications/mimeinfo.cache
Someone else hopefully knows how to do this in Windows and can chime in.
Edit: Stealing from the other answers:
Linux:
xdg-open [filename]
Cygwin:
cygstart [filename]
And for completeness, here's a link to a previous question about how to detect which operating system you are running on: Detect OS from bash Script
I'd like if there were a different answer to this but I think you'll have to check the file association configs for every desktop environment and file manager out there (so, nautilus, konqueror, thunar, mc... all in different places and in different formats AFAIK), as well as ascertaining which one of these the user is actually using...
If someone has a different idea I'm keen to hear it.

Resources