How to tell if a program is installed on Linux in Haskell - bash

I'm creating a script that uses an external program that interacts with a server.
I want to test first that the program is installed before trying to use it.
I looked up the preferred way to tell if a program was installed and found this post:
How can I check if a program exists from a Bash script?
TLDR: It recommends "command -v <prog-name>" over "which <prog-name>" since it is POSIX compatible. The command should return 0 if the program was found, >0 otherwise.
So I used readProcessWithExitCode from System.Process as follows
readProcessWithExitCode "command" ["-v", "<some-program>"] ""
I get the following error when testing in GHCI
Exception: command: readCreateProcessWithExitCode: posix_spawnp: does not exist (No such file or directory)
I tried to use 'which' on 'command'. It tells me it does not exist although I can use it and it works as described in the man pages in my terminal.
What's going on here and how do I see if something is installed using Haskell?
Some system information:
GHC: 9.0.2
resolver: lts-19.11
"I use Arch btw"

I recommend that you simply run the program you want to run, and catch the exception you get if it isn't available. Like this:
catch
(callProcess "lol-this-does-not-exist" []) -- or whatever
(\e -> if isDoesNotExistError e then putStrLn "yikes" else throw e)

Related

Rust std::process with special characters

I've got a very simple rust program but its not doing quite what I'd expect. Running on Windows, using a powershell prompt, I can do the following to display the path:
echo "%PATH%"
and I have a simple Rust program with:
Command::new("echo")
.arg("%PATH%")
.spawn()
.expect("ls command failed to start");
The command will launch and run, but it outputs:
%PATH%
instead of the path contents, like I'd expect. Other commands which don't use special characters seem to work as expected, so I suspect its related to handling them but I don't see a way in Rust to make the command any more primitive than it already is.
I've tried various formatting but it either fails to run the command or does the same.
I also tried using $env:path, but this always fails to run from Rust with a cannot find the path specified error.
Are there any suggestions for handling this? I could write the contents to a file and run the file instead, but running these types of commands from other languages directly works fine so I think it should work from Rust as well.
Thanks!
Update:
Managed to get the expected results from by using:
let out = Command::new("cmd")
.arg("/C")
.arg("echo %PATH%")
.spawn()
.expect("ls command failed to start");
}
I think the question got interpreted a bit differently, as getting the path was just an example of a larger issue I was seeing. Updating with the above solved my larger issue as well.
As the comment by French says: Spawning the process does not include the Powershell-environment, which would expand %PATH% to it's actual content before launching the process.
You need to get the content of PATH via std::env yourself or lookup the Powershell documentation on how to launch a subprocess inside a powershell-session.
As others have mentioned, it's not the special characters, it's the fact that those special characters are interpreted by powershell before the "echo" program runs at all.
Using https://doc.rust-lang.org/cargo/reference/environment-variables.html as a reference for how to look up environment variables, try something like this:
use std::env;
fn main() {
let cur_path = env::var("PATH").unwrap();
println!("Environment is: {}", cur_path);
}
You can try this here: https://play.rust-lang.org/
You can then feed cur_path into your "Command::new" if you wish. The trick is that powershell substitutes that argument BEFORE launching echo, which you may not have known, whereas when you execute the echo program directly, you have to do that substitution yourself.

Compiler outputs the errors under Wine, but not on Windows

I've got .mqh source code file with syntax error, for example created by the following command:
echo some_error > fail.mqh
Now, I'm using Metaeditor compiler to check the syntax and my goal is to print the errors to the standard output (CON), instead of logging them to the file (/log:file.log). See: Compiling.
The following syntax works fine on Linux/macOS as follow (also under wine cmd.exe):
$ wine metaeditor.exe /s /log:CON /compile:fail.mqh
??fail.mqh : information: Checking 'fail.mqh'
fail.mqh(1,1) : error 116: 'some_error' - declaration without type
fail.mqh(1,1) : error 161: 'some_error' - unexpected end of program
: information: Result 2 error(s), 0 warning(s)
Please note that the /log parameter is required, otherwise the compiler doesn't print anything by default. So if /log is specified, then by default it logs the compilation result to the file. And I'm using special CON device to display the errors.
The problem is when I'm running the same command on Windows (cmd), then I've got no output:
> metaeditor.exe /s /log:CON /compile:fail.mqh
Same for CON:/con: as well. Also on PowerShell.
Although CON works for echo, e.g.: echo test > CON.
I could assume it could be a bug of the compiler, but then it works fine under Wine. Why would this work only under Wine?
Is there another way of outputting the errors to the terminal screen on Windows, instead of log file?
Note: You can install compiler from the site or download the binary (32bit or 64bit) to test above.
Clarification: My main blocker for using two separate commands (compile and print the error log after that) is that CI test may fail before the errors are printed, which makes the tests useless and it's a story for another question. So my goal is to check the syntax and print the errors at one go.
According to Support Team, Metaeditor application does not have a console, so it cannot output logs to the screen. So it seems wine handles special CON device differently. I've reported the issue to the Service Desk and it's still open, so they may implement the console support in the future.
Currently the only workaround is to use type command for output log file to console after compiling the files (or emulate it under wine). Even if the compiler could display it to the console, it won't work properly with CI either (in terms of handling the error codes), because logic of return exit of metaeditor.exe is completely broken as it returns the number of successfully compiled files instead of the error code (e.g. if you compile 20 files, you'll get 20 error code?!)! So relying on return exit of metaeditor.exe is a mistake and MQL team isn't planning to fix it anyway, since they say this is how it should work in their opinion.

How can I make a local Git hook run a Windows executable and wait for it to return?

I'm working in a Windows environment. I have a Git repository and am writing a custom pre-commit hook. I am much more comfortable writing a quick and dirty console application in C# than trying to figure out Perl syntax so that's the route I'm going.
My .git/hooks/precommit file looks like this:
#!/bin/sh
start MyHelperApp.exe
And this works somewhat. As you can see I have a compiled helper application in the root of the repo directory (and it is .gitignore'd), and this does indeed launch my application successfully when I call git commit. However, it doesn't wait for the process to finish nor does it seem to care what the return code of the process is. I assume this is because start is asynchronous and it returns a 0 exit code every time.
I have reason to suspect that the start process which is getting called here is not the native Windows start command, because I tried changing it to start /wait MyHelperApp.exe but this had no effect. Also trying to call MyHelperApp.exe directly gives a "command not found" error, and so does changing start to call. I suspect that start is an emulated bash command and it's running the bash version instead of the Windows version?
Anyways, my helper app does return different exit codes depending on different conditions, so it'd be great if those could be used. (Pre-commit hooks fail if a program in the script returns any exit code besides zero.) How might I go about utilizing this?
Call the executable directly, don't use start.
Also trying to call MyHelperApp.exe directly gives a "command not found" error
If the PATH variable doesn't contain a . entry, bash won't look in the current directory to find executables. Call ./MyHelperApp.exe to make it explicit that it should be run from the current directory.

Xeon Phi cannot execute binary file

I am trying to execute a binary file on a xeon phi coprocessor, and it is coming back with "bash: cannot execute binary file". So I am trying to find how to either view an error log or have it display what's happening when I tell it to execute that is causing it not work. I have already tried bash --verbose but it didn't display any additional information. Any ideas?
You don't specify where you compiled your executable nor where you tried to execute from.
To compile a program on the host system to be executed directly on the coprocessor, you must either:
if using one of the Intel compilers, add -mmic to the compiler
command line
if using gcc, use the cross-compilers provided with the MPSS
(/usr/linux-k1om-4.7) - note, however, that the gcc compiler does not
take advantage of vectorization on the coprocessor
If you want to compile directly on the coprocessor, you can install the necessary files from the additional rpm files provided for the coprocessor (found in mpss-/k1om) using the directions from the MPSS user's guide for installing additional rpm files.
To run a program on the coprocessor, if you have compiled it on the host, you must either:
copy your executable file and required libraries to the coprocessor
using scp before you ssh to the coprocessor yourself to execute the
code.
use the micnativeloadex command on the host - you can find a man page
for that on the host.
If you are writing a program using the offload model (part of the work is done using the host then some of the work is passed off to the coprocessor), you can compile on the host using the Intel compilers with no special options.
Note, however, that, regardless of what method you use, any libraries to be used with an executable for the coprocessor will need themselves to be built for the coprocessor. The default libraries exist but any libraries you add, you need to build a version for the coprocessor in addition to any version you make for the host system.
I highly recommend the articles you will find under https://software.intel.com/en-us/articles/programming-and-compiling-for-intel-many-integrated-core-architecture. These articles are written by people who develop and/or support the various programming tools for the coprocessor and should answer most of your questions.
Update: What's below does NOT answer the OP's question - it is one possible explanation for the cannot execute binary file error, but the fact that the error message is prefixed with bash: indicates that the binary is being invoked correctly (by bash), but is not compatible with the executing platform (compiled for a different architecture) - as #Barmar has already stated in a comment.
Thus, while the following contains some (hopefully still somewhat useful) general information, it does not address the OP's problem.
One possible reason for cannot execute binary file is to mistakenly pass a binary (executable) file -- rather than a shell script (text file containing shell code) -- as an operand (filename argument) to bash.
The following demonstrates the problem:
bash printf # fails with '/usr/bin/printf: /usr/bin/printf: cannot execute binary file'
Note how the mistakenly passed binary's path prefixes the error message twice; If the first prefix says bash: instead, the cause is most likely not a problem of incorrect invocation, but one of trying to a invoke an incompatible binary (compiled for a different architecture).
If you want bash to invoke a binary, you must use the -c option to pass it, which allows you to specify an entire command line; i.e., the binary plus arguments; e.g.:
bash -c '/usr/bin/printf "%s\n" "hello"' # -> 'hello'
If you pass a mere binary filename instead of a full path - e.g., -c 'program ...' - then a binary by that name must exist in one of the directories listed in the $PATH variable that bash sees, otherwise you'll get a command not found error.
If, by contrast, the binary is located in the current directory, you must prefix the filename with ./ for bash to find it; e.g. -c './program ...'

Error when using lua filename.lua

I'm very new to lua, and I've been trying to create a lua file using TextWrangler, then execute the file in my terminal (using a Mac). I create the following in a textwrangler file:
for i=1,10 do
print ("Hello")
end
print ("That's all!")
and I save it as test.lua. I then move this file into the lua directory, ~/lua-5.2.3. I then start lua, and use the following command:
lua test.lua
and I get the following error:
stdin: 1: syntax error near 'test'
What am I doing wrong here? I've looked everywhere online for a solution to, what I assume, is a very simple oversight on my part, but I have found nothing. My first thought was that I was putting the file in the wrong place, but I have moved it everywhere with the same result.
You can execute script typing lua test.lua in terminal.
If you enter interpreter mode, you can use dofile "test.lua". There is no lua command(function ) there, unless you declare it somewhere.
There is a PIL section about stand-alone interpreter usage and more up-to date reference section.

Resources