I'm using net.neoremind.sshxcute SSH Java API library to connect to a sftp server and execute a shell script present on that server.
My Shell Script does a simple job of moving files from that SFTP location to a HDFS location on some other machine.
Currently, there's no way to report if any of the files are not moved due to any reason such as connection failure, file with illegal name, empty file etc.
I wonder, how can I show that set of information for each failed file move from shell command back to Java code ?
This is my sample code :
// e.g sftpScriptPath => /abc/xyz
// sftpScriptCommand => sudo ./move.sh
// arguments => set of arguments to shell script.
task = new ExecShellScript(sftpScriptPath, sftpScriptCommand, arguments);
result = m_SshExec.exec(task);
if(result.isSuccess && result.rc == 0)
{
isSuccessful = true;
s_logger.info("Shell script executed successfully");
s_logger.info("Return code : " + result.rc);
s_logger.info("Sysout : " + result.sysout);
}
else
{
isSuccessful = false;
s_logger.info("Shell script execution failed");
s_logger.info("Return code : " + result.rc);
s_logger.info("Sysout : " + result.sysout);
}
The Result object returned from the exec method call includes:
exit status or return code (Result.rc),
standard output (stdout) (Result.sysout),
standard error (stderr) (Result.error_msg), and
an indication of success, based on return code and output (Result.isSuccess).
So, if you are committed to the current method of executing a shell script using the sshxcute framework, then the simplest way would be to have the move.sh script provide information about any failures while moving files. This could be done via a combination of return codes and standard output (stdout) and/or standard error (stderr) messages. Your Java code would then obtain this information from the returned Result object.
Related
I am trying to execute a script file at (location : /home/id/scripts/) from my java code. Below is my java code :
Process process = null;
scriptfileName = "myScript.sh" ;
executeCmd = "/home/id/scripts/" +scriptfileName ;
process = new ProcessBuilder(executeCmd).start();
When I try to run the script using above code, only initial some lines are getting executed like, I placed 2 echo statement, only the first one is getting printed and rest below lines which has update DataBase statements are not executing. Same script file if I am running directly using command - {ksh sctiptfileName}, it successfully executes and updates DB.
I want to run shell script inside watch service class to run the shell after new file add to folder.
Watch service is working perfectly but when I want to add Runtime.getRuntime().exec("home/user/test.sh"); I recived error.
I just add Runtime after this:
// Dequeueing events
Kind<?> kind = null;
for(WatchEvent<?> watchEvent : key.pollEvents()) {
// Get the type of the event
kind = watchEvent.kind();
if (OVERFLOW == kind) {
continue; //loop
} else if (ENTRY_CREATE == kind) {
// A new Path was created
Path newPath = ((WatchEvent<Path>) watchEvent).context();
// Output
System.out.println("New path created: " + newPath);
Runtime.getRuntime().exec("home/user/test.sh")
What I have to do?
I thing problems with running script have nothing to do with WatchService, since you don't post actual exception that is throws (that would help a lot) I can only guess what is wrong, so please check this:
Script doesn't have permission to execute (easily fixable by chmod +x path/to/script.sh) - in that case you would get IOException with message like Permission denied or similar
System cannot find your script, since you are using relative path (no / at the beginning of script name) in that case ether use full script name e.g. /home/user/foo/script.sh or use proper relative path ../foo/script.sh - you should check if script exists before running it via exec (How do I check if a file exists in Java?)
Beware that script may be called with working directory of running Java program - so you should pass newly created file path as parameter to script to make it independent of its location
I followed tutorial that you were using with code:
if (OVERFLOW == kind) {
continue; //loop
} else if (ENTRY_CREATE == kind) {
// A new Path was created
Path newPath = ((WatchEvent<Path>) watchEvent).context();
// Output
System.out.println("New path created: " + newPath);
Runtime.getRuntime().exec(new String[] { "/home/xxx/foo.sh", newPath.toString() });
}
and script:
#!/bin/bash
echo "FILE CREATED: $1" >> /home/xxx/watch_dir.log
and it worked without any errors.
I'm writing a jython code which use Jsch to run some shell instructions on a remote machine. I need to wait a specific shell instruction has finished before continuing the exectuion of the jython code on my local machine (=need to synchronize shell code on a remote machine).
To do that, when the specific shell instruction has finished i create a text file in the remote machine. Then in my jython code I open an sftp channel and try periodically to get the file (using the sftp.exception and a "while true" loop). The code wait until the file is downloaded.
My problem is that even when the file is created, the jsch function "get" doesn't manage to download the file and keep sending "sftp.exception : no such file or directory" .That makes me locked up in an infinite loop.
Here is my code :
#We generate the info files for each class of the classlist
for classname in classlist:
print ("Generating information file (format : .out) for the class %s " % (classname))
#We open a shell channel and run the commands "windchill shell" and then "InfoReport.sh classname".
channel_generate = gl_session.openChannel('shell')
ops = channel_generate.getOutputStream()
ps = PrintStream(ops, True)
channel_generate.connect()
ps.println("windchill shell")
ps.println('rm ' + self.wt_home + '/tmp/' + classname + '.txt')
#The following instruction is the one i need to synchronize
ps.println(self.wt_home + '/bin/' + self.command + " " + classname)
#I create a file to detect the end of the previous instruction
ps.println('echo ok > ' + self.wt_home + '/tmp/' + classname)
ps.println('exit')
ps.close()
#Here we wait until the synchro file is created.
#We connect an sftp server and test every 4 seconds if we can retrieve the file.
channel_synchro = gl_session.openChannel('ftp')
channel_synchro.connect()
#This loop is broken when the get is successful
while True:
try:
channel_synchro.get(self.wt_home + '/tmp/' + classname,'/home/dev/temp')
break
except jsch.SftpException:
time.sleep(4)
#Disconnect and close de sftp channel
channel_synchro.disconnect()
channel_synchro.close()
#Disconnect and close the shell channel
channel_generate.disconnect()
channel_generate.close()
I have tried different solutions : other type of loops, create a new channel in each iteration of the "while true" loop, i have thought about user rights problem, i have checked if the paths are exact and they are, i have checked if the sftp function of my machine works and it works.
Nothing works, i'm still not able to solve this problem
I am writing a small Scala script to generate PGP signatures for all the files in the current directory. This is what I wrote:
object PGPSign {
def main(args: Array[String]) {
signFilesInDirectory(new java.io.File("."))
}
def signFilesInDirectory(dir: java.io.File) {
if(!dir.exists())
throw new java.io.FileNotFoundException
if(!dir.isDirectory())
throw new RuntimeException("Expecting directory")
println("Signing files in: " + dir.getAbsolutePath())
for{ file <- dir.listFiles
if !file.isDirectory //ignoring directories
val fileName = file.getName()
if !fileName.startsWith(".") //ignoring hidden files
} {
("gpg -ab " + fileName).!!
}
}
}
In the console, the command gpg -ab FILE_NAME will request a password. When I execute my scala script I got this exception at the point of invoking the external command:
gpg: cannot open tty `/dev/tty': Device not configured
Exception in thread "main" java.lang.RuntimeException: Nonzero exit value: 2
at scala.sys.package$.error(package.scala:27)
at scala.sys.process.ProcessBuilderImpl$AbstractBuilder.slurp(ProcessBuilderImpl.scala:131)
at scala.sys.process.ProcessBuilderImpl$AbstractBuilder.$bang$bang(ProcessBuilderImpl.scala:101)
at PGPSign$$anonfun$signFilesInDirectory$3.apply(PGPSign.scala:25)
at PGPSign$$anonfun$signFilesInDirectory$3.apply(PGPSign.scala:20)
at scala.collection.TraversableLike$WithFilter$$anonfun$foreach$1.apply(TraversableLike.scala:743)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:34)
at scala.collection.mutable.ArrayOps.foreach(ArrayOps.scala:38)
at scala.collection.TraversableLike$WithFilter.foreach(TraversableLike.scala:742)
at PGPSign$.signFilesInDirectory(PGPSign.scala:20)
at PGPSign$.main(PGPSign.scala:11)
at PGPSign.main(PGPSign.scala)
I have the idea this is related to the fact that the external command (gpg in this case) requests some input.
If this is what is creating the problem(?), what is the easiest general way to make any external command (requesting any amount of inputs) to work when executed from Scala ?
gpg expects to be able to read from/write to a tty, which is not available unless gpg is started from an interactive shell. You should use the --no-tty option to disable this behavior. Also, you probably want batch mode, enabled with --batch.
I want to perform an svn delete from my Grails app. I tested out both of the following in the Grails console:
"svn delete /usr/share/mydir".execute()
Runtime.getRuntime().exec("svn delete /usr/share/mydir")
In both cases, a instance of java.lang.Process is returned, but the command does not get executed (/usr/share/mydir is not deleted).
This behaviour only happens when the app is running on Linux (Ubuntu). If I run it on Windows, the command does get executed.
Update
Following Tim's advice in the comments, I changed the command so that it captures the process output:
def process = "svn delete /usr/share/mydir".execute()
def out = new StringBuilder()
process.waitForProcessOutput(out, new StringBuilder())
println "$out"
I now see that the reason it's failing is because:
error svn: Can't open file '/usr/share/mydir/.svn/lock': Permission
denied
The below code works fine for me on CentOS.
def scriptCom="/folderlocation/shellscript.sh"
println "[[Running $scriptCom]]"
def proc = scriptCom.execute()
def oneMinute = 60000
proc.waitForOrKill(oneMinute)
if(proc.exitValue()!=0){
println "[[return code: ${proc.exitValue()}]]"
println "[[stderr: ${proc.err.text}]]"
return null
}else{
println "[[stdout:$revisionid]]"
return proc.in.text.readLines()
}