call a bash script from a scala program ( in windows ) - windows

I have a bash script called test ( I made a simple one just for test )
#!/bin/sh
echo "Hello world"
I tried to call it from a simple scala program in several ways :
1 ) "C:\\Users\\me\\project\\myProject\\scripts\\test.bash"!!
and I got this: error CreateProcess error=193, %1 is not a valid Win32 application
I found in internet that I should add the path for bash.exe because I am in windows
So I made this:
val p = Process("C:\\Users\\me\\DevTools\\cmder\\vendor\\git-for-windows\\bin\\bash.exe C:\\Users\\me\\project\\myProject\\scripts\\test.bash")
I have no errors ,
but I don't know if it works, In fact I did this
print(p.run().toString)
It gives an "UNDIFNED"
My question: How to call the script ? and How to manipulate the result: I want to test the output.
Thanks

find the solution
val commandLine: String = " path_to\bash.exe path_to\script.bash"
val result= Process(commandLine).lineStream
and then you can manipulate your result , for my cases I tested that it should contain an expected string ..

Related

Cannot write files from Lua in Scite on Windows 10?

Using Scite 4.1.3 on Windows 10.
I tried the following Lua script:
function TestFile()
mycontent = "Hello World"
mytmpfilename = os.tmpname()
os.execute("echo aaaa > " .. mytmpfilename) -- create file explicitly;
mytmpfile = io.popen(mytmpfilename, "w") -- w+ crashes Scite in Windows!
mytmpfile:write(mycontent)
mytmpfile:close()
print("readall " .. mytmpfilename .. ": " .. io.popen(mytmpfilename, "r"):read("*a"))
end
If I run this, I get printed:
readall C:\Users\ME\AppData\Local\Temp\s8qk.m:
... which means Lua could not even read this file?! And also, this stupid Windows Explorer prompt shows up:
At end, the content of the C:\Users\ME\AppData\Local\Temp\s8qk.m is still just aaaa.
So obviously, mytmpfile:write part fails silently, and nothing new is written in the file - the only thing that wrote to the file is the echo aaaa > ... executed by cmd.exe via os.execute.
So my question is - how can I write a file with Lua in Scite on Windows? Preferably, without having that stupid "How do you want to open this file?" prompt show up?
Eh, I think I got it ...
See, the OP example uses io.popen - and, if we look at https://man7.org/linux/man-pages/man3/popen.3.html it says:
popen, pclose - pipe stream to or from a process
(emphasis mine).
So, basically, if under Windows I try to do io.popen(filename), then apparently tries to find the process that would be the default "opener" for that file type ... and also therefore the prompt I'm being shown in the OP (and therefore, I could never read or write the files accessed -- or rather, not accessed -- in that way).
However, Programming in Lua : 21.2 – The Complete I/O Model actually uses io.open (notice, no p for process); and then the files seem to open for read/write fine.
So, corrected example from OP should be:
function TestFile()
mycontent = "Hello World"
mytmpfilename = os.tmpname()
-- os.execute("echo aaaa > " .. mytmpfilename) -- create file explicitly; -- no need anymore, with io.open
mytmpfile = io.open(mytmpfilename, "w+") -- w+ crashes Scite in Windows, but only if using io.popen; is fine with io.open!
mytmpfile:write(mycontent)
mytmpfile:close()
print("readall " .. mytmpfilename .. ": " .. io.open(mytmpfilename, "r"):read("*a"))
end

How to pass "args" while using Intellij IDEA [example list 3.11 in Odersky's Scala book (2nd Ed)]

I basically try to run the example 3.11 in Odersky's book (Programming in Scala). I am using Intellij IDE. While runing the code, the "else" branch got executed.
The screen capture is here:
The source is here in case you need it to try:
package ch3
import scala.io.Source
object l3p11 extends App{
def widthOfLength(s: String) = s.length.toString.length
if (args.length > 0){
val lines = Source.fromFile(args(0)).getLines().toList
val longestLine = lines.reduceLeft(
(a, b) => if (a.length > b.length) a else b
)
val maxWidth = widthOfLength(longestLine)
for (line <- lines){
val numSpaces = maxWidth - widthOfLength(line)
val padding = " " * numSpaces
println(padding + line.length + "|" + line)
}
}
else
Console.err.println("Please enter filename")
}
The reason, I think, is becuase I did not pass args correctly (say here I want to pass the source file l3p11.scala as the args). I tried several option, but have not find a way to pass the args correctly for the code to be executed in the "if" branch. There are two directions in my mind to resolve this problem:
1. Find the right way to pass args in Intellij IDE
Run Scala in commond line, a similar command such as
$ scala l3p11.scala l3p11.scala
should be able to pass the args correctly. But my current setting gives "bash: scala: command not found". I currently use scala REPL to run scala code following the set up given in Odersky's Coursera course on Scala. I think I need to change the set up in orde run scala directly, instead of using "sbt->console" to invoke the scala interpreter like what I am doing now.
Any suggestion on either direction (or other directions that I have not thought of) to resolve the problem is welcome.
Update 1:
Direction 2 works after I reinstall scala. (My to be corrected understanding is that the installation of sbt does not provide an executable binary of scala to be included in the environment list for Windows. Therefore, scala command cannot be found before). After installation of scala directly:
$ scala l3p11.scala l3p11.scala
gives the expected results. But I still have not figured out how to get this result with Intellij IDEA.
Update 2:
I revisited the "Program arguments" option after Joe's confirmation. The reason I was not be able to get it work before was that I only add "l3p11.scala". Adding the complete path from working directory "src/main/scala/ch3/l3p11.scala" solved the problem. The result is as following:
To pass command-line arguments when running a program in IntelliJ IDEA, use the "Edit Configurations …" menu item under "Run". Choose the entry for your main program. There's a "Program arguments" text field where you specify the arguments to pass to the program.
I'm not super familiar on how it will run on windows but if you are able to run it directly from the command line then I think you'll need to compile first, that's the scalac command. So:
$ scalac l3p11.scala
then you can run just with the class name, not sure if you would need quotes on the arg:
$ scala l3p11 l3p11.scala

Why does argparse fail to recognise an argument when a Python script is called directly?

I have a simple script like this (based on the docs for argparse):
def Main():
parser = argparse.ArgumentParser()
parser.add_argument("issuenumber", help="Create a local branch based on the specified issue number", type=int)
args = parser.parse_args()
if args.issuenumber:
print("Starting work on issue #"+str(args.issuenumber))
if __name__ == "__main__":
Main()
When I run it however, it never recognises the argument I'm passing it:
C:\Projects\PyTools>Gritter.py 1
usage: Gritter.py [-h] issuenumber
Gritter.py: error: the following arguments are required: issuenumber
If I call the script via a python call it works however:
C:\Projects\PyTools>python Gritter.py 1
Starting work on issue #1
If I print out sys.argv I get:
C:\Projects\PyTools>Gritter 1
['C:\\Projects\\PyTools\\Gritter.py']
C:\Projects\PyTools>Python Gritter.py 1
['Gritter.py', '1']
So I guess something is not passing on the arguments when the script is called directly. I wonder if there's anything that can be done so that the script can be called directly?
The C\ indicates you are using Windows. You have take extra effort to ensure that this 'direct call' passes arguments through to python.
Looking up windows shebang I find, from Python docs that you need to use
#!/usr/bin/python -v
to pass arguments
See https://docs.python.org/3/using/windows.html
argparse uses sys.argv. If that only has the script name then the call isn't passing arguments.
Based on mckoss` answer, I modified the following registry key:
HKEY_CLASSES_ROOT\Applications\python.exe\shell\open\command
From this:
"C:\Python34\python.exe" "%1"
To this:
"C:\Python34\python.exe" "%1" %*
And now my script works as I'd previously expected.

Haskell Noob In Need of Assistance

This is a bit long, so bear with me!
I'm having a bit of trouble working with a Haskell program, that I have to use as part of a uni project. For reference, it's Casper.
So, you're supposed to execute a script, which is actually a Bash script to invoke Hugs interpreter like this:
exec $HUGSBIN/hugs $HUGSARGS +p"Casper> " $FILES
Where $FILES points to a Main.lhs file.
After this, I need to invoke a function "compile" with a path to a file, in the interpreter.
I need to perform the above in a scripted manner. I need this automated because I'm writing a program that will call on Casper in the background.
So I compiled the .lhs file. Now I want to execute the "compile" function but I have no idea how this is done. I try:
./Main compile <a path>
from the command line but it returns me an error about a file "test" not found. Upon investigation, I see these lines in the Main.lhs file:
>main :: String -> IO()
>main = compile "test"
>compile :: String -> IO()
>compile s = catch (compile0 False s) handler
[...snipped]
The 2nd line solves this question. Now my question is, how do I invoke the "compile" function and pass a path to it after I have compiled main.lhs? From the interpreter, I just type "compile " and it works, but I can't get the same to work after compiling the main.lhs and executing from the command line? Any ideas why? Is there any way I can script Hugs if all else fails?
Thank you for any assistance!
You may access the command-line arguments passed to a Haskell program via getArgs. For example, it sounds like you want a main function that does something like this:
>main = do
> args <- getArgs
> case args of
> [] -> putStrLn "What file did you want me to compile?"
> [filename] -> compile filename
> _ -> putStrLn "I only compile one file at a time."
Modify to taste.
Replace main with
main = getArgs >>= \(arg1:_) -> compile arg1
This will pass the first command line argument (arg1) to compile instead of "test", and ignore the rest (_). You may need to add
import System
or
import System.Environment
I can't remember what is needed in hugs for this.

Alternative to system() and _popen() on Windows

This is related to: How do I read the results of a system() call in C++?
I am trying to do the exact the same thing only that my program needs to pass 'multiple parameters with spaces' to the command. I need the command line output and the exit code from the process.
Example: An example with Textpad. The application I'm really using prints stuff on stdout.
string command1 = "\"C:\Program Files\TextPad 5\Textpad.exe\" C:\readme0.txt";
string command2 = "\"C:\Program Files\TextPad 5\Textpad.exe\" \"C:\read me2.txt\"";
cout << system(command1.c_str()) << endl;
cout << system(command1.c_str()) << endl;
Output:
0
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.
1
The first call to system passes and second one fails with the error above. _popen in Windows works similarly on Windows so no help there. I can easily do this on Linux as I can escape spaces in the parameters without having to use quotes.
An alternative is to write a huge chunk of non-cross-platform code as listed here:
http://msdn.microsoft.com/en-us/library/ms682499(VS.85).aspx
But in case I want to avoid that, are there any alternatives to system() and _popen() on Windows?
Thanks!
The lowest level Windows API function used by _popen() and system() is CreateProcess().
However CreateProcess() is not that simple to use - especially when you want to get the process'es output or write to the process'es input.
CreateProcess() will definitely work with file names that contain space characters (as long as they are written in quotation marks the way you did that).
The following solves the spaces in the path problem. Catching the output of the command is much more difficult, however:
#include <string>
#include <cstdlib>
using namespace std;
int main() {
string cmd = "\"c:\\program files\\notepad++\\notepad++.exe\"";
system( cmd.c_str() );
return 0;
}
A bunch of utility libraries have taken that chunk of non-portable code and wrapped it up with a portable interface. For an example, see Qt's QProcess.
I do this (note - this is VB.NET code), so I can write the output of the command to my log file (it's wrapped in a RunCommand() method):
Try
Dim myprocess As New Process()
myprocess.StartInfo.FileName = "C:\Program Files\TextPad 5\Textpad.exe"
myprocess.StartInfo.RedirectStandardOutput = True
myprocess.StartInfo.UseShellExecute = False
' inArgs are the arguments on the command line to the program
myprocess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
myprocess.StartInfo.Arguments = "C:\readme0.txt"
' the dir to set as default when the program runs
Then myprocess.StartInfo.WorkingDirectory = "C:\Program Files\TextPad 5\"
myprocess.Start()
' grab a reader to the standard output of the program
procReader = myprocess.StandardOutput()
' read all the output from the process
While (Not procReader.EndOfStream)
procLine = procReader.ReadLine()
' write the output to my log
writeNotes(procLine)
End While
procReader.Close()
Catch ex As Exception
' Write the error to my log
writeErrors("Couldn't execute command "C:\Program Files\TextPad 5\Textpad.exe", ex)
End Try
I think ShellExecute() is what you're looking for.
Never use system() in Windows !
Just redirect i/o handles.

Resources