Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

This is related to How to execute a remote command on a local file?

I wrote a simple Java program that prints the first line of a file -

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.OutputStreamWriter;

public class ReadFirstLine 
{
    public static void main(String[] args) throws Exception 
    {
       String filename = args[0];

       BufferedReader iR  = new BufferedReader (new FileReader(filename));
       BufferedWriter oW = new BufferedWriter(new OutputStreamWriter(System.out));

       outputWriter.write(iR.readLine());

       iR.close();
       oW.close();
    }
}

Then, I created a symlink in the /usr/bin directory called ReadFirstLine which points to the /usr/local/RFL/ReadFirstLine script -

#! /bin/bash

java -cp "/usr/local/RFL" ReadFirstLine "$1" 

(/usr/local/RFL has ReadFirstLine.class)

Now, I can call ReadFirstLine from any directory like this -

$ ReadFirstLine simplefile.txt

This same script I want to call from a different machine. So from the remote machine I tried -

$ ssh username@xyz ReadFirstLine < localfile.txt  

However, I got the error

Exception in thread "main" java.io.FileNotFoundException:  (No such file or directory)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.<init>(FileInputStream.java:146)
    at java.io.FileInputStream.<init>(FileInputStream.java:101)
    at java.io.FileReader.<init>(FileReader.java:58)
    at ReadFirstLine.main(ReadFirstLine.java:12)

How can I modify the Java Program / script such that this remote invocation works?

share|improve this question
    
Why don't you use head -1? –  cuonglm Apr 14 at 17:47

3 Answers 3

up vote 3 down vote accepted
+100

I don't know anything about Java, but I can show you a proof of concept. Say we have localfile.txt:

Here is the local file.

and on the remote machine, we have remote.sh:

#!/bin/bash
cat /dev/stdin

Note that the script on the remote machine invokes a program which reads from stdin. Then pass the contents of localfile.txt to your ssh command:

user@local:~$ cat localfile.txt | ssh user@remote remote.sh
Here is the local file.

Your Java program is trying to read a file which does not exist on the remote machine. I guess you could try to mimic a local file.

Change remote.sh to:

#!/bin/bash
cat "$@"

and invoke it with

user@local:~$ cat localfile.txt | ssh user@remote 'remote.sh <(cat /dev/stdin)'
Here is the local file.

I think it would be easier to change that part in your Java program to read from stdin.

I guess things might get messy if localfile.txt contains anything that might be interpreted by the shell as expandable (such as *), but that's for you to figure out.

share|improve this answer
    
Thanks for your answer. –  Wes Apr 14 at 19:01
    
Your addendum is strange because that exact syntax worked for me. –  Wes Apr 14 at 19:45
1  
oh, yes, that's correct. I need to go to bed I guess. I was still using the modified version of remote.sh which expected a file descriptor, not stdin. It will work if you are reading from stdin. –  user61786 Apr 14 at 20:02
    
Thanks! .......... –  Wes Apr 14 at 20:02

The problem is that the shell redirection (<) sends the file over the ssh tunnel. And the Java class is expecting not the file, but a string with the "filename" of a local file that will be read with a FileReader.

Instead of passing the filename to the FileReader, read from the standard input.

InputStreamReader isReader = new InputStreamReader(System.in);
BufferedReader iR  = new BufferedReader (isReader);

Used this as a reference: http://stackoverflow.com/questions/5724646/how-to-pipe-input-to-java-program-with-bash

Now your class will be:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.OutputStreamWriter;
import java.io.InputStreamReader;

public class ReadFirstLine 
{
    public static void main(String[] args) throws Exception 
    {
       String filename = args[0];
       System.out.println(filename);

       //BufferedReader iR  = new BufferedReader (new FileReader(filename));
       InputStreamReader isReader = new InputStreamReader(System.in);
       BufferedReader iR  = new BufferedReader (isReader);

       BufferedWriter oW = new BufferedWriter(new OutputStreamWriter(System.out));

       //outputWriter.write(iR.readLine());
       System.out.println(iR.readLine());

       iR.close();
       oW.close();
    }
}

But for this task I would definitely use instead:

head -1 filename.txt

:)

share|improve this answer
    
Thanks. I wish I could accept your answer as well along with the one I accepted. –  Wes Apr 14 at 19:00
    
"ssh username@xyz ReadFirstLine < localfile.txt" works. I tested. No need to pipe the file to ssh. imgur.com/obzG292 –  user159841 Apr 15 at 0:05
    
@user159841 sorry, I was very tired when I wrote that comment and was using the wrong test script. –  user61786 Apr 15 at 4:51

The local file, by definition, is on your local machine. The java program is on a remote machine. The remote machine does not know about your local file, and in any production situation probably does not have permission to read it. I can think of three general approaches to this situation:

1) Change your Java program to read from stdin instead of from a file. Then your current syntax $ ssh username@xyz ReadFirstLine < localfile.txt will work.

2) scp your file from the local machine to the remote machine before running the java program. scp localfile.txt username@xyz Make sure you put it in the directory which will be the working directory for your java program.

3) Mount a remote directory in your remote machine to you local machine. This has the most setup, but is the solution that get closest to what you are asking for. It will allow you to make changes to the file locally, and the remote machine will see the changes. See this answer for more about mounting a remote direcotry.

http://stackoverflow.com/questions/232269/how-to-mount-a-linux-directory-from-a-different-pc-to-your-local-linux-pc

The argumante to the java program will be the path as it appears on the remote machine.

On local machine: /directory/which/has/been/shared/localfile.txt

On remote machine: /path/to/mounted/directory/on/remote/host/localfile.txt

$ ssh username@xyz ReadFirstLine < /path/to/mounted/directory/on/remote/host/localfile.txt
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.