Write an executable .sh file with Java for OSX - java

So I am trying to write an .sh file that will be executable, this is how I'm currently writing it:
Writer output = null;
try {
output = new BufferedWriter(new FileWriter(file2));
output.write(shellScriptContent);
output.close();
} catch (IOException ex) {
Logger.getLogger(PunchGUI.class.getName()).log(Level.SEVERE, null, ex);
}
So that writes the file just fine, but it is not executable. Is there a way to change the executable status when I write it?
Edit: To further clarify, I am trying to make it execute by default, so that for instance, if you double clicked the generated file, it would automatically execute.

You can call File.setExecutable() to set the owner's executable bit for the file, which might be sufficient for your case. Or you can just chmod it yourself with a system call with Process.
Alas, full-powered programmatic alteration of file permissions isn't available until Java 7. It'll be part of the New IO feature set, which you can read more about here.

You'd need to chmod it, and you can probably do it by exec'ing a system command like such:
Really all you'd need is to fire off something like this:
Runtime.getRuntime().exec("chmod u+x "+FILENAME);
But if you want to keep track of it more explicitly can capture stdin / stderr then something more like:
Process p = Runtime.getRuntime().exec("chmod u+x "+FILENAME);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
Which I got from here:
http://www.devdaily.com/java/edu/pj/pj010016/pj010016.shtml
Update:
Test program:
package junk;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class Main{
private String scriptContent = '#!/bin/bash \n echo "yeah toast!" > /tmp/toast.txt';
public void doIt(){
try{
Writer output = new BufferedWriter(new FileWriter("/tmp/toast.sh"));
output.write(scriptContent);
output.close();
Runtime.getRuntime().exec("chmod u+x /tmp/toast.sh");
}catch (IOException ex){}
}
public static void main(String[] args){
Main m = new Main();
m.doIt();
}
}
On linux if you open up a file browser and double click on /tmp/toast.sh and choose to run it, it should generate a text file /tmp/toast.txt with the words 'yeah toast'. I assume Mac would do the same since it's BSD under the hood.

In Java 7 you can call Files.setPosixFilePermissions. Here is an example:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Set;
class FilePermissionExample {
public static void main(String[] args) throws IOException {
final Path filepath = Paths.get("path", "to", "file.txt");
final Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(filepath);
permissions.add(PosixFilePermission.OWNER_EXECUTE);
Files.setPosixFilePermissions(filepath, permissions);
}
}

On Mac OS X, besides chmod +x, you have to give a .command extension to your shell script if you want to launch it with a double-click.

This answer I wrote for the question how do I programmatically change file permissions shows a chmod example via a native call using jna, which should work on Mac OS X.

Related

Access to root application support macos java

I need to save data inside the /Library/Application Support/ of macOS within a java application. To access the user application data, I know I can use System.getProperty("user.home") but I want the one from the root, not the user. I see some applications storing data inside this, is there a way to do it within java?
If not in java, i am loading a obj-c library, is it possible in obj-c to elevate privileges so my java application have access to that folder?
If this is an interactive program then using authopen would be perfect, otherwise I would use launchd.
I just noticed that this answer had been deleted. Why would someone delete the right answer?
Here is a simplified example to illustrate the use of authopen to answer the question:
package macos4;
import java.io.File;
import java.io.IOException;
public class MacOS4 {
public static void main(String[] args) throws IOException, InterruptedException {
String destinationFileName = "/Library/Application Support/tempFile/";
ProcessBuilder builder = new ProcessBuilder("/usr/libexec/authopen", "-c", "-w", "-a", destinationFileName);
builder.redirectInput(new File("src/resources", "input.txt"));
builder.redirectError(ProcessBuilder.Redirect.INHERIT);
builder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process process = builder.start();
process.waitFor();
process.destroy();
}
}
This will create tempFile if it does not exist and write to it the contents of input.txt from the resources package. It will pop up for authentication:
which means there is no need to pipe the password to the subprocess.
For very important considerations regarding the need to prevent external processes to block on IO buffers see this.
What if you want your job to run unattended? Time for launchd, but keep in mind that the entire program will run as root, unlike the interactive option, which I posted above, where only the file operations run as root. I wrote this simple program that I want to run every 5 minutes. Every time it runs it will add a line to "/Library/Application Support/tempFile" with the current date and time; every 30 minutes it will overwrite the file and start over, but keeping just the last timestamp. Here is the program:
package maclaunchd;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.attribute.FileTime;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MacLaunchd {
public static void main(String[] args) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
Date date = new Date();
File tempFile = new File("/Library/Application Support/tempFile");
if (!tempFile.exists()) {
tempFile.createNewFile();
}
FileTime creationTime = (FileTime) Files.getAttribute(tempFile.toPath(), "creationTime");
boolean append = (System.currentTimeMillis() - creationTime.toMillis() <= 1800000);
FileWriter fw = new FileWriter(tempFile, append);
try (BufferedWriter bw = new BufferedWriter(fw)) {
bw.write(sdf.format(date) + "\n");
}
} catch (IOException ex) {
Logger.getLogger(MacLaunchd.class.getName()).log(Level.SEVERE, null, ex);
throw new RuntimeException(ex);
}
}
}
Then I created a launchd job definition which I called “maclaunchd.MacLaunchd.daemon.plist”. Here it is:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>GroupName</key>
<string>wheel</string>
<key>KeepAlive</key>
<false/>
<key>Label</key>
<string>maclaunchd.MacLaunchd.daemon</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/java</string>
<string>-jar</string>
<string>/Users/enta/NetBeansProjects/MacLaunchd/dist/MacLaunchd.jar</string>
</array>
<key>RunAtLoad</key>
<false/>
<key>StandardErrorPath</key>
<string>/Users/enta/NetBeansProjects/MacLaunchd/dist/err.log</string>
<key>StandardOutPath</key>
<string>/Users/enta/NetBeansProjects/MacLaunchd/dist/out.log</string>
<key>StartInterval</key>
<integer>300</integer>
<key>UserName</key>
<string>root</string>
<key>WorkingDirectory</key>
<string>/Users/enta/NetBeansProjects/MacLaunchd/dist/</string>
</dict>
</plist>
Next I copied the file to the right place, loaded it and started it:
sudo cp maclaunchd.MacLaunchd.daemon.plist /Library/LaunchDaemons
sudo launchctl load /Library/LaunchDaemons/maclaunchd.MacLaunchd.daemon.plist
sudo launchctl start maclaunchd.MacLaunchd.daemon
If you cat "/Library/Application Support/tempFile" you will see the date being written to it every 5 minutes. To stop, unload and remove the job run:
sudo launchctl stop maclaunchd.MacLaunchd.daemon
sudo launchctl unload /Library/LaunchDaemons/maclaunchd.MacLaunchd.daemon.plist
sudo rm /Library/LaunchDaemons/maclaunchd.MacLaunchd.daemon.plist
Now you have two options to write to "/Library/Application Support/”.

How to Invoke "Powershell script file" from Java in Linux operating system

Class:-
=====================
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class TestPowershell {
public static void main(String[] args) throws IOException
{
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("cmd powershell \"\\Test\\Powershell\\powershell.ps1\" ");
proc.getOutputStream().close();
InputStream is = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(isr);
String line;
while ((line = reader.readLine()) != null)
{
System.out.println(line);
}
reader.close();
proc.getOutputStream().close();
}
}
I am trying to execute a powershell file by using java in linux environment , i am getting exceptions (above i attached class and exceptions), kindly provide me a test class which can execute powershell script file in linux. Thanks in advance
1st download the FreeSSHD http://www.freesshd.com/?ctt=download in your windows(server). make sure run it as Administrator.
for setup FreeSSHD follow this URL http://www.techrepublic.com/blog/tr-dojo/set-up-a-free-ssh-server-on-windows-7-with-freesshd/ after setup you can ssh that windows system from linux or using putty.
to execute powershell script from linux to remote windows system using java
package com.sysvana.router.config;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;
public class Test {
static String hostname = "10.1.10.60";
static String username = "administrator";
static String password = "P#ssw0rd";
public static void main(String[] args) throws IOException {
Connection conn = new Connection(hostname);
conn.connect();
boolean isAuthenticated = conn.authenticateWithPassword (username, password);
if (isAuthenticated == false){
System.out.println("authentication failed");
}
System.out.println(isAuthenticated);
Session sess = conn.openSession ();
sess.execCommand ("powershell C:/Users/Administrator/Desktop/test.ps1");
InputStream stdout = new StreamGobbler (sess.getStdout ());
BufferedReader br = new BufferedReader (new InputStreamReader (stdout));
while (true)
{
String line = br.readLine ();
if (line == null) break;
System.out.println (line);
}
System.out.println ("Exit code" + sess.getExitStatus ());
sess.close ();
conn.close ();
}
}
use Ganymed SSH-2 jar http://www.ganymed.ethz.ch/ssh2/
Your problem is that you're not actually trying to run PowerShell. You're using this:
runtime.exec("cmd powershell \"\\Test\\Powershell\\powershell.ps1\" ")
which means it's trying to run a file called cmd, which is not part of Linux.
Also, in another part of the code, you're trying to run powershell.exe. Typically, Linux programs don't have a .exe extension. You may have ported your Java application from Windows, but you need to be aware that Linux is different. It doesn't come with Powershell as standard, and doesn't use .exe file extension.
You can install PowerShell at https://github.com/PowerShell/PowerShell.
On Linux, PowerShell (once installed from the above) is invoked with the pwsh command. You will need to change your Java program accordingly.
Thanks for all your answers.
Finally, I got to know while working with PowerShell we should run the script in windows OS only because Microsoft is the owner for PowerShell and they give more features in Windows OS.
what I did is, I ran the script in Windows OS & generated a CSV file and kept in SFTP folder, by using java I loaded my file and processed my next process.

How to run NPM Command in Java using Process Builder

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
public class TestUnZip {
public static void main(String[] args) throws IOException, InterruptedException{
String destFolder="E:\\TestScript";
/*
* Location where the Nodejs Project is Present
*/
System.out.println(destFolder);
String cmdPrompt="cmd";
String path="/c";
String npmUpdate="npm update";
String npm="npm";
String update="update";
File jsFile=new File(destFolder);
List<String> updateCommand=new ArrayList<String>();
updateCommand.add(cmdPrompt);
updateCommand.add(path);
updateCommand.add(npmUpdate);
runExecution(updateCommand,jsFile);
}
public static void runExecution(List<String> command, File navigatePath) throws IOException, InterruptedException{
System.out.println(command);
ProcessBuilder executeProcess=new ProcessBuilder(command);
executeProcess.directory(navigatePath);
Process resultExecution=executeProcess.start();
BufferedReader br=new BufferedReader(new InputStreamReader(resultExecution.getInputStream()));
StringBuffer sb=new StringBuffer();
String line;
while((line=br.readLine())!=null){
sb.append(line+System.getProperty("line.separator"));
}
br.close();
int resultStatust=resultExecution.waitFor();
System.out.println("Result of Execution"+(resultStatust==0?"\tSuccess":"\tFailure"));
}
}
The Above Program works fine, but this program is depend on Windows Machine, I want to run the same program in other Machine as well.
1) NPM is a Command comes as a bundle of NodeJS. (I run NodeJS as a service, I have defined the Environment Variable, so I can run npm update command from any folder)
2) I can't find a work around to run the npm update command without using the "cmd", "/c". If I do I get following error
Exception in thread "main" java.io.IOException: Cannot run program "npm update" (in directory "E:\TestScript"): CreateProcess error=2, The system cannot find the file specified
at java.lang.ProcessBuilder.start(Unknown Source)
3) Do we have option of Running the npm update command as a parameter of Node.exe. If so can anyone provide me the proper work around.
4) Same as I like, I use mocha framework to run the test script and result generates the .xml file.
5) I want mocha command also being invoked using process builder.
The problem is that ProcessBuilder does not respect the PATHEXT variable on Windows.
It's true there is no npm binary on Windows, there's a npm.cmd. My best solution is to check the platform. Something like this:
static boolean isWindows() {
return System.getProperty("os.name").toLowerCase().contains("win");
}
static String npm = isWindows() ? "npm.cmd" : "npm";
static void run() {
Process process = new ProcessBuilder(npm, "update")
.directory(navigatePath)
.start()
}
In Unix or Linux os , the PathBuilder takes the default environment path , so we have to change the environment path and run the npm command through the bash.
import java.io.File;
import java.util.Map;
public class CommandExecutor {
public void exceuteCommand(String commandString,String
directoryToExecuteCommand) {
try {
ProcessBuilder processBuilder = new ProcessBuilder(new String{"bash", "-c",commandString});
Map<String, String> env = processBuilder.environment();
processBuilder.directory(new File(directoryToExecuteCommand));
String envPath="/home/admin123/.nvm/versions/node/v10.15.3/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin";
env.put("PATH",envPath);
processBuilder.start();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
CommandExecutor commandExecutor=new CommandExecutor();
commandExecutor.exceuteCommand("npm install", "/home/admin123/Desktop");
}
}

Create and write a file into hdfs from my local machine

I have two systems connected in the network. One is hdfs running. I want to create a file and write data from my another machine.
package myorg;
import java.io.*;
import java.util.*;
import java.net.*;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.conf.*;
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapred.*;
import org.apache.hadoop.util.*;
public class Write1{
public static void main (String [] args) throws Exception{
try{
System.out.println("Starting...");
Path pt=new Path("hdfs://10.236.173.95:8020/user/jfor/out/gwmdfd");
FileSystem fs = FileSystem.get(new Configuration());
BufferedWriter br=new BufferedWriter(new OutputStreamWriter(fs.create(pt,true)));
// TO append data to a file, use fs.append(Path f)
String line;
line="Disha Dishu Daasha dfasdasdawqeqwe";
System.out.println(line);
br.write(line);
br.close();
}catch(Exception e){
System.out.println("File not found");
}
}
}
I compiled it using
javac -classpath hadoop-0.20.1-dev-core.jar -d Write1/ Write1.java
Created a jar using
jar -cvf Write1.jar -C Write1/ .
Run command
hadoop jar Write1.jar myorg.Write1
If i run this, i am getting
starting...
File not found
What could be the reason? If i run this program, in my hadoop machine, it works fine [I replaced ip with localhost].
Error is at BufferedWriter line. It says "File Not found". what does it mean? I used fs.creat. Then it should create if it doesn't exist. Isn't?
java.lang.IllegalArgumentException: Wrong FS: hdfs://10.72.40.68:8020/user/jfor/..... expected localhost:8020
So i modified the following line
FileSystem fs = FileSystem.get(new URI("hdfs://<ip>:8020"),new Configuration());
It says Connection refused. What could be the reason

How to direct std input from file in Eclipse

How we can take input from the file in the Eclipse?
Just like we direct the I/O from the file from the command line.
java MyProgram < input.txt >output.txt
I am unable to direct the input.
but output directing is easy.
Just go->Run->Run->Configurations->Common
Why don't you use File instead of redirection?
Your program will have a fileName as input and then write the result in a file.
If you need necessarily use the default in you can do something like this:
System.setIn(new FileInputStream("testFile.txt"));
a sample of how it works follows:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class TestSystemIn {
public static void main(final String[] args) throws IOException {
// prepare test
FileOutputStream fos = new FileOutputStream("testFile.txt");
fos.write("testToken".getBytes());
// configure env
System.setIn(new FileInputStream("testFile.txt"));
// perform read test
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("read: " + br.readLine());
}
}
The output could be done in the same way using:
System.setOut(new PrintStream("testFile.txt"));

Categories