Jump to content
Claris Engage 2025 - March 25-26 Austin Texas ×

This topic is 5157 days old. Please don't post here. Open a new topic instead.

Recommended Posts

  • Newbies
Posted

Can anyone confirm that it is possible to get the Run Shell Script module to work on Windows, and if so, what is the magic? I am using the latest version of ScriptMaster, 4.0.2, and Filemaker Pro 11 Advanced on WinXP, and trying to run very simple commands like PATH or DIR does not work at all even though it does work in cmd.exe. I managed to get it to work on Mac OS X, although I found it to need quotes, but nothing works on Windows for me. In fact, if I try to run the command "cmd.exe" it locks up FmPro.

Thanks in advance.

The error message is:

java.io.IOException: Cannot run program "PATH": CreateProcess error=2, The system cannot find the file specified

Parameters:

{shellScript=PATH}

---Script---

Script:

String[] commands = tokenize( shellScript );

Process process = Runtime.getRuntime().exec( commands );

process.waitFor();

exitValue = process.exitValue();

outputResult = process.getInputStream().getText("utf-8");

errorResult = process.getErrorStream().getText("utf-8");

if (exitValue != 0)

throw new Exception(errorResult);

return outputResult;

public static String[] tokenize( String input ) {

input = input.trim();

String token, nextDelim = "t "";

StringTokenizer st = new StringTokenizer(input, nextDelim, true );

List result = new LinkedList();

while( st.hasMoreTokens() ) {

String lastValue = "";

while( true ) { //Loop until a word is found

token = st.nextToken( nextDelim );

if( """.equals( token ) ) {

if( """.equals( nextDelim ) ) break; //This is the closing quote

else nextDelim = """; //This is the opening quote

} else if( " ".equals( token ) || "t".equals( token ) ) {

if( lastValue.length() > 0 ) break;

} else if( "".equals( token ) ) {

i...

Posted

The code below, will bring up a directory of C: in XP:

Bear in mind also, you must escape -- so for instance, to get a directory of c:temp, command[3] would instead, be set to c:temp below

This returns standard output and standard error, all concactenated together.

---------------------------------------------

String[] command = new String[4];

command[0] = "cmd";

command[1] = "/C";

command[2] = "dir";

command[3] = "c:";

Process p = Runtime.getRuntime().exec(command);

BufferedReader stdInput = new BufferedReader(new

InputStreamReader(p.getInputStream()));

BufferedReader stdError = new BufferedReader(new

InputStreamReader(p.getErrorStream()));

// read the output from the command

String s = "";

String a = "";

while ((s = stdInput.readLine()) != null) {

a = a + s + "n";

}

// read any errors from the attempted command

while ((s = stdError.readLine()) != null) {

a = a + s + "n";

}

return a;

Posted

I've just re-written the shell script module. Here is the docs, which will be in the next release of ScriptMaster:

This executes a command in the underlying OS. On Windows, the command should be a DOS script; on OS X it would be a UNIX shell script.

If waitForOutput is 'true', then the output of the shell process is returned. This example will return the list of logged in users in OS X. If it is 'false', then no errors or result are reported, and the function returns immediately while the shell command runs in the background.

Here is the actual code to paste in:


boolean isMac = System.getProperty("os.name").contains("Mac");

String[] cmds;

if( isMac ) cmds = ["/bin/sh", "-c", command];

else cmds = ["cmd.exe", "/C", command];



Process process = Runtime.getRuntime().exec( cmds );

if( Boolean.valueOf( waitForOutput ) ) { //Wait for command to finish

	if( process.waitFor() == 0 ) { //Successful

		return process.getInputStream().getText();

	} else { //Error when running command

		throw new RuntimeException( process.getErrorStream().getText() );

	}

} else { //Don't wait, return immediately

	return "Executed shell command: " + command;

}

Posted

Hi Jesse

Thanks for following up this issue. I hope you won't mind early feedback, but tried this code with the Shell script I want to have work. Sorry for the long file paths:

cupsfilter /Volumes/Macintosh HD/Users/pracau/Documents/SolMan_System/Trainer_Resources/Steve_Bruechert/CHC60102/CHCAD3A Activity.rtf >> /Volumes/Macintosh HD/Users/pracau/Documents/SolMan_System/Trainer_Resources/Steve_Bruechert/CHC60102/CHCAD3A Activity.pdf

Unfortunately it came up with the error:

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:

Script1.groovy: 1: unexpected char: 0xA0 @ line 1, column 1.

 

^

1 error

Parameters:

{Shellscript=cupsfilter /Volumes/Macintosh HD/Users/pracau/Documents/SolMan_System/Trainer_Resources/Steve_Bruechert/CHC60102/CHCAD3A Activity.rtf >> /Volumes/Macintosh HD/Users/pracau/Documents/SolMan_System/Trainer_Resources/Steve_Bruechert/CHC60102/CHCAD3A Activity.pdf}

---Script---

Script:

 

boolean isMac = System.getProperty("os.name").contains("Mac");

String[] cmds;

if( isMac ) cmds = ["/bin/sh", "-c", command];

else cmds = ["cmd.exe", "/C", command];

Process process = Runtime.getRuntime().exec( cmds );

if( Boolean.valueOf( waitForOutput ) ) { //Wait for command to finish

    if( process.waitFor() == 0 ) { //Successful

        return process.getInputStream().getText();

    } else { //Error when running command

        throw new RuntimeException( process.getErrorStream().getText() );

    }

} else { //Don't wait, return immediately

    return "Executed shell command: " + command;

}

I hope that this will help you crack it.

John

 

Posted

Somehow the character encoding is getting messed up and you're getting invisible characters in the script. Please send me a direct message with your email address and I'll send you a copy of a FileMaker file with the script.

  • Newbies
Posted

Hi Jesse,

Thanks for your response. On WinXP, I pasted in your code but had to add some to get it to partially work (below). It still throws an error but won't list it, and the Text Result is:

"Executed shell command: [D, I, R]"

It does not seem to actually be running the cmd.exe command however, since the cmd window never comes up. I tried the tokenize(shellScript) part but that was worse.

Jim

boolean isMac = System.getProperty("os.name").contains("Mac");

String[] cmds;

String[] command = shellScript;

String[] waitForOutput;

if( isMac ) cmds = ["/bin/sh", "-c", command];

else cmds = ["cmd.exe", "/C", command];

Process process = Runtime.getRuntime().exec( cmds );

if( Boolean.valueOf( waitForOutput ) ) { //Wait for command to finish

if( process.waitFor() == 0 ) { //Successful

return process.getInputStream().getText();

} else { //Error when running command

throw new RuntimeException( process.getErrorStream().getText() );

}

} else { //Don't wait, return immediately

return "Executed shell command: " + command;

}

Posted

Thank you guys for reporting these issues. I've re-written the shell script module (again!), and I've made these changes:

* Now reads the stderr and stdout streams in separate threads. This fixes the case where long output was blocking the script from finishing (thanks Frank / fseipel for researching this)

* Now closes the streams immediately if waitForOutput is false. This fixes a problem where the shell command could take a long time to execute.

* Added a timeout parameter. This is specified in seconds. Use 0 to wait forever.

There is no change to the plugin, just the ScriptMaster.fp7 file. I've uploaded a copy here:

http://demo.360works.com/temp/ScriptMaster.fp7.zip

Please give it a shot and let me know if it seems to work, if so I will include it in the next public deployment of ScriptMaster.

  • Newbies
Posted

Congratulations, Jesse! It works like a charm using WinXP even with a fairly complicated script that uses a piped input to a command with multiple parameters. The command takes awhile so I have to increase the timeout to around 60 seconds, but it works. If the timeout is not long enough it gives a long error message but the command will still go to completion, as shown when it is set to write to an external file.

Thanks very much and I am glad that it finally works on WinXP.

Jim

  • Newbies
Posted

Jesse,

One quick question, now that the shell script module is working on WinXP, if I call this calculation in a script that is run from FM Server Adv 11, will it run a shell script on the server or the client machine? I need it to run on the server, but I am not sure which will actually happen. If it will run on the Server, do we need to purchase an Enterprise License and does this exist for the ScriptMaster Plugin?

Thanks so much,

Jim

Posted

Glad to hear that it's working! I'll move this script into the FM file that will be bundled with the next release.

1) Don't forget that you can do a zero timeout which means wait indefinitely.

2) Scripts executed on the client run on the client, even if the client is opening the file as a guest of the server. If you want the script to run on FileMaker Server, set up a schedule in the server admin to run that script. It is also possible (but a bit tricky) to install the plugin on the Web Publishing Engine and run it there.

3) There is no extra charge or license needed to run ScriptMaster on the server. Either the free ScriptMaster plugin, or plugins generated from ScriptMaster Advanced ($95) will run on FileMaker Server.

Posted

How about an amended date on the functions?? or a version number in the top lines??

This might make it easier to copy single updated items out of your version into our own, where there are lots of other scripts and development going on...

This is so updated that a creation date in 2007 does not indicate how modern the content is....

  • 2 weeks later...
Posted (edited)

The revised script works very well indeed.

However on Windows (XP sp3 in my case), I still encounter some problems when the returned result contains diacritics. (See attached example)

I tried to edit the Groovy script by asking him to read the streams and the buffers as UTF-8, but this didn't improve my results.

Can you please point me the right direction to take.

SM_GetVBSResult.zip

Edited by Guest
Posted

Hi Clement, I've fixed the issue with international characters. Thanks for reporting it.

Change this line:

Reader r = new InputStreamReader( inputStream )




to this:




Reader r = new InputStreamReader( inputStream, "utf-8" )

This occurs in two different places within the script, so be sure to change both (although probably only the first one, which reads stdout, is important).

I'll include this in the next deployment of ScriptMaster.

Posted

Hi Jesse,

Thank you for your reply.

Before I submit my example in the previous post, I tried this change of course, but unfortunately it doesn't solve the problem.

In doing so, all diacriticals take the form of Unicode character U+FFFD / 65533

(UTF-8 hex: 0xEFBFBD, UTF-16 Hex 0xFFFD)

ex:

"23 Ao�t 1935. Les na�fs et fr�les gar�ons venus de D�sseldorf ont mang� tous les g�teaux � la cr�me fouett�e. Pour eux c'�tait No�l!"

Apparently, there is another place in the script where characters aren't considered as due UTF-8.

So I tried to place some ".GetText("utf-8")" in the script; but when I run the command, the only thing I get are type-casting errors...

Clem

  • 3 weeks later...
Posted

Can you try with this ScriptMaster file?

http://demo.360works.com/temp/ScriptMaster.fp7.zip

I've tried it with the exact same test string, and all of the international characters work OK.

Posted

Hi Jesse,

Thank you for your reply and the file.

Obviously, I brought changes to the script according to your initial recommendations and these changes correspond verbatim to those in your posted document.

But alas, none of these changes has provided a solution to the (my) problem.

Meanwhile I've pushed my investigations a little further and it seems like (conditional used !) when reading/printing via a DOS console it is necessary to use the CP850 encoding or a variant thereof.

Cp437 MS-DOS United States, Australia, New Zealand, South Africa

Cp850: MS-DOS Latin-1

Cp852 MS-DOS Latin-2

Cp858: Variant of Cp850 With Euro character

http://download-llnw.oracle.com/javase/1.5.0/docs/guide/intl/encoding.doc.html

By changing the UTF-8 in favor of CP858, the string returned by the console prints correctly ALL accented characters except for symbols like "€", "¥" and other less common.

That's where I'm at the moment.

I don't know, but it's may be necessary to make an additional encoding transformation ?

Posted

Jesse,

Sorry to have to bug you again with this problem.

The change you made does the job nicely on the Mac side.

On Windows (XP), however, I am having to call up a program to convert .doc files to .pdf format.

The commandline works using the Dos 'run' system but when I try it using the RunShellScript module, I hit:

java.lang. IllegalArgummentException

at java.lang.ProcessImpl.(Unknown Source)

at java.lang.ProcessImpl.start(Unknown Source)

at java.lang.ProcessBuilder.start(Unknown Source)

The offending commandline:

"C:Program FilesSoftinterface, IncConvert DocConvertDoc" /S "H:SolMan_SystemTrainer_ResourcesSteve_Bruecher tCHC60102PSPMNGT605A Activity.doc" /T "H:SolMan_SystemTrainer_ResourcesSteve_Bruecher tCHC60102PSPMNGT605A Activity.pdf" /F9 /C12 /M2

I have tried changing the 30 to 0 and up to 300 but it makes no difference.

I hope that you may have some advice as I really need this to work.

I've also tried another plug in, yooShell, and the command above works with it, on the XP platform at least.

So there is still an issue with the ShellScript module. Sorry to have to report that.

Posted (edited)

Try shortening the command to DOS8.3 (8 character filename + 3 character extension) and eliminating the quotes enclosing the command. This fixes the problem, e.g.

c:PROGRA~1SOFTIN~1CONVER~1CONVER~2.exe /S "H:SolMan_SystemTrainer_ResourcesSteve_Bruecher tCHC60102PSPMNGT605A Activity.doc" /T "H:SolMan_SystemTrainer_ResourcesSteve_Bruecher tCHC60102PSPMNGT605A Activity.pdf" /F9 /C12 /M2

To get shortened path names, type "command" while already in a DOS window. Then use DIR /X to show files and directories.

Alternately, place the entire command in double quotes, e.g. use

""C:Program FilesSoftinterface, IncConvert DocConvertDoc" /S "H:SolMan_SystemTrainer_ResourcesSteve_Bruecher tCHC60102PSPMNGT605A Activity.doc" /T "H:SolMan_SystemTrainer_ResourcesSteve_Bruecher tCHC60102PSPMNGT605A Activity.pdf" /F9 /C12 /M2"

I wonder if it might be simpler to fix all these Windoze problems with spaces and command line arguments, by simply taking the command and writing it to a batch file, then executing the batch file. The rationale for this is that getruntime().exec has a lot of idiosyncracies that cause it to fail. Running the shell script from a batch file eliminates all these problems. Alternately the command could just be enclosed in quotes.

If this is done, you will have the functionality that 'if it runs in DOS, it will run in ScriptMaster' exactly as typed. Granted, it will generate an extra batch file, but it can simply be overwritten each time command runs, and is typically going to be very short. The script could even delete the batch file upon completion.

One other feature I like about this method is that the command line will come back as well, with the current path, because that will be part of the standard output. In this case, the run shell script code would be as indicated below (just paste into code window). Changes from original are in blue.

This will process the command properly without any changes to the original DOS command. It deletes the temp batch file only if command succeeded. If Mac version exhibits these issues, this could probably be altered to run on Macs, but I don't think the ".bat" extension would be recognized, perhaps you would use ".sh"? I defer to the Mac experts on that but below code works fine on Windoze.

If you install OpenOffice, the MSWord-->PDF conversion can also be achieved without need to pay for 3rd party software such as Convert Doc.

Also, since Convert Doc doesn't produce standard output or error, it might be better just running it using inbuilt Filemaker send event command rather than SM? If there is no standard output or error to interpret, run shell script isn't required, or am I missing something? SM would be useful to bring the log file back into an FM field.

The batch file also permits stacking commands, since you can separate them by a RETURN and include more than one, though & between commands also works for that purpose.

String TempPath = [color:blue]System.getProperty("java.io.tmpdir"); // Store temporary path e.g. c:UsersOwnerAppDataLocalTemp

boolean isMac = System.getProperty("os.name").contains("Mac");

String[] cmds;

if( isMac ) cmds = ["/bin/sh", "-c", command];

else [color:blue]// for Winblows, create a batch file with the requisite commands for WYSIWYG functionality

{cmds = ["cmd.exe", "/C", TempPath + "runme.bat"];

new File( TempPath + "runme.bat" ).write(command ); // Write command to batch file

}

final Process process = Runtime.getRuntime().exec( cmds );

final InputStream inputStream = process.getInputStream();

final InputStream errorStream = process.getErrorStream();

final StringBuffer stdout = new StringBuffer();

final StringBuffer stderr = new StringBuffer();

if( Boolean.valueOf( waitForOutput ) ) { //Wait for command to finish

Thread stdoutThread = new Thread( "stdout reader" ) {

public void run() {

try {

Reader r = new InputStreamReader( inputStream, "utf-8" );

char[] buff = new char[1024];

int charsRead;

while( ( charsRead = r.read( buff ) ) != -1 ) {

stdout.append( buff, 0, charsRead );

}

[color:blue]if( !isMac ) new File( TempPath + "runme.bat" ).delete(); // Delete the temporary batch file if running under Windoze

} catch( IOException e ) {

throw new RuntimeException( e );

}

}

};

stdoutThread.start();

Thread stderrThread = new Thread( "stderr reader" ) {

public void run() {

try {

Reader r = new InputStreamReader( errorStream, "utf-8" );

char[] buff = new char[1024];

int charsRead;

while( ( charsRead = r.read( buff ) ) != -1 ) {

stderr.append( buff, 0, charsRead );

}

} catch( IOException e ) {

throw new RuntimeException( e );

}

}

};

stderrThread.start();

final int timeoutMilliseconds = Integer.valueOf( timeout ) * 1000;

if( timeoutMilliseconds > 0 ) {

final Thread mainThread = Thread.currentThread();

new Thread("timeout thread") {

public void run() {

try {

Thread.sleep( timeoutMilliseconds );

mainThread.interrupt();

} catch( InterruptedException e ) {

//Ignore

}

}

}.start();

}

try {

if( process.waitFor() == 0 ) { //Successful

stdoutThread.join(); //Wait for all output to be read

return stdout.toString();

} else { //Error when running command

stderrThread.join(); //Wait for entire error message to be read

throw new RuntimeException( stderr.toString() );

}

} catch( InterruptedException e ) {

throw new RuntimeException("Process was interrupted; error output is: " + stderr.toString() );

}

} else { //Don't wait, return immediately

inputStream.close();

errorStream.close();

return "Executed shell command: " + command;

}

Edited by Guest

This topic is 5157 days old. Please don't post here. Open a new topic instead.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.