2011-07-19 35 views
8

Tôi cố gắng để đạt được hai điều:Làm thế nào để thực hiện unix lệnh thông qua Windows/Cygwin sử dụng Java

  1. Tôi đang chạy Cygwin trên Windows7 để thực hiện các lệnh shell unix tôi và tôi cần để tự động hóa quá trình bằng cách viết một ứng dụng Java. Tôi đã biết cách sử dụng vỏ cửa sổ thông qua Java bằng cách sử dụng 'Process class' và Runtime.getRuntime().exec("cmd /c dir"). Tôi cần có khả năng thực hiện tương tự với các lệnh unix: ví dụ: ls -la và v.v. Tôi nên xem xét điều gì?

  2. Có cách nào để ghi nhớ trạng thái của trình bao không? giải thích: khi tôi sử dụng: Runtime.getRuntime().exec("cmd /c dir"), tôi luôn nhận được danh sách thư mục chính của mình. Nếu tôi làm Runtime.getRuntime().exec("cmd /c cd <some-folder>") và sau đó thực hiện lại Runtime.getRuntime().exec("cmd /c dir"), tôi vẫn sẽ nhận được danh sách thư mục chính của mình. Có cách nào để nói cho quá trình nhớ trạng thái của nó, giống như một vỏ thông thường không?


Dường như dòng bash lệnh bằng Paulo đề xuất không hoạt động:

C:\cygwin\bin>bash -c ls -la 
-la: ls: command not found 

tôi đang gặp khó khăn để tìm ra các technicalities.

Đây là mã của tôi:

p = Runtime.getRuntime().exec("C:\\cygwin\\bin\\bash.exe -c ls -la"); 
reader2 = new BufferedReader(new InputStreamReader(p.getInputStream())); 
line = reader2.readLine(); 

line rốt cục sẽ có một giá trị null.


tôi thêm này để .bash_profile của tôi:

#BASH 
export BASH_HOME=/cygdrive/c/cygwin 
export PATH=$BASH_HOME/bin:$PATH 

tôi thêm vào sau cũng như:

System Properties -> Advanced -> biến Môi trường -> user variebales -> biến: BASH, giá trị: c:\cygwin\bin

Vẫn không có gì ...

Tuy nhiên, nếu tôi thực hiện thay vào đó, nó hoạt động!

p = Runtime.getRuntime().exec("c:\\cygwin\\bin\\ls -la ~/\"Eclipse_Workspace/RenameScript/files copy\""); 
+0

OK, hãy xem. Trực tiếp thực thi 'ls.exe' dường như hoạt động, nếu chúng ta đưa ra đường dẫn đúng. –

+0

ok, vậy làm thế nào để làm cho bash nhận ra nó khi sử dụng đối số -c? –

+0

Tôi nghĩ khi thực hiện với '-c', nó không thực thi' .bashrc' của bạn. Bạn có thể thử đặt đường dẫn với đối số 'envp' thành' exec'. (Tôi sẽ thêm vào câu trả lời của mình.) –

Trả lời

8

1. Gọi lệnh unix:

Bạn chỉ cần gọi shell unix của bạn (chẳng hạn như bash giao với Cygwin) thay vì cmd.

bash -c "ls -la" 

nên làm.Tất nhiên, nếu lệnh của bạn là một chương trình bên ngoài, bạn có thể chỉ đơn giản gọi nó là trực tiếp:

ls -la 

Khi bắt đầu này từ Java, cách tốt nhất là sử dụng các biến thể mà phải mất một mảng chuỗi, như sau đó bạn don' t có Java để cho nó phân tích để xem nơi các đối số bắt đầu và ngừng:

Process p = 
    Runtime.getRuntime().exec(new String[]{"C:\\cygwin\\bin\\bash.exe", 
              "-c", "ls -la"}, 
           new String[]{"PATH=/cygdrive/c/cygwin/bin"}); 

thông báo lỗi trong ví dụ của bạn (ls: command not found) dường như để chứng minh rằng bash của bạn không thể tìm thấy lệnh ls. Có lẽ bạn cần phải đặt nó vào biến PATH (xem ở trên để biết cách làm điều này từ Java).

Có thể thay vì /cygdrive/c/cygwin/bin, tên thư mục phù hợp sẽ là /usr/bin.

(Tất cả mọi thứ là một chút phức tạp ở đây bằng cách làm cầu nối giữa Unix và Windows ước ở khắp mọi nơi.)

Các đơn giản ls lệnh có thể được gọi như thế này:

Process p = Runtime.getRuntime().exec(new String[]{"C:\\cygwin\\bin\\ls.exe", "-la"}); 

2. Gọi nhiều lệnh:

Về cơ bản có hai cách gọi nhiều lệnh trong một trình bao:

  • chuyển tất cả chúng cùng một lúc đến trình bao; hoặc
  • chuyển chúng tương tác với vỏ.

Đối với cách đầu tiên, bạn chỉ cần cung cấp cho nhiều lệnh như là đối số để lựa chọn -c, cách nhau bằng ; hoặc \n (một dòng mới), như thế này:

bash -c "cd /bin/ ; ls -la" 

hoặc từ Java (thích ứng với ví dụ trên):

Process p = 
    Runtime.getRuntime().exec(new String[]{"C:\\cygwin\\bin\\bash.exe", 
              "-c", "cd /bin/; ls -la"}, 
           new String[]{"PATH=/cygdrive/c/cygwin/bin"}); 

Tại đây vỏ sẽ phân tích cú pháp dòng lệnh và thực thi dưới dạng tập lệnh. Nếu nó chứa nhiều lệnh, tất cả chúng sẽ được thực thi, nếu shell không bằng cách nào đó thoát ra trước đó vì một lý do nào đó (như lệnh exit). (Tôi không chắc chắn nếu Windows cmd hoạt động theo cách tương tự. Vui lòng kiểm tra và báo cáo.)

Thay vì chuyển bash (hoặc cmd hoặc bất kỳ shell nào bạn đang sử dụng) các lệnh trên dòng lệnh , bạn có thể chuyển chúng qua luồng đầu vào của Quy trình.

  • Một vỏ bắt đầu trong "chế độ đầu vào" (ví dụ như một trong đó có cả các -c lựa chọn cũng không phải là tranh luận shell script file) sẽ đọc đầu vào từ suối, và giải thích dòng đầu tiên như là một lệnh (hoặc một vài người) .
  • Sau đó, nó sẽ thực thi lệnh này. Lệnh này có thể đọc thêm đầu vào từ luồng, nếu nó muốn.
  • Sau đó, trình bao sẽ đọc dòng tiếp theo, diễn giải nó dưới dạng lệnh và thực thi.
  • (Trong một số trường hợp, trình bao phải đọc nhiều hơn một dòng, ví dụ như các chuỗi dài hoặc các lệnh được soạn thảo như nếu hoặc vòng lặp.)
  • Điều này sẽ tiếp tục cho đến khi kết thúc luồng (ví dụ: stream.close() ở bên cạnh bạn) hoặc thực hiện lệnh rõ ràng exit (hoặc một số lý do khác để thoát).

Dưới đây sẽ là một ví dụ cho điều này:

Process p = Runtime.getRuntime().exec(new String[]{"C:\\cygwin\\bin\\bash.exe", "-s"}); 
InputStream outStream = p.getInputStream(); // normal output of the shell 
InputStream errStream = p.getInputStream(); // error output of the shell 
// TODO: start separate threads to read these streams 

PrintStream ps = new PrintStream(p.getOutputStream()); 
ps.println("cd /bin/"); 
ps.println("ls -la"); 
ps.println("exit"); 
ps.close(); 
+0

Vui lòng đặt mã vào câu hỏi của bạn (có nút chỉnh sửa), nó không thể đọc được dưới dạng nhận xét. –

+0

Ngoài ra, tôi nghĩ bạn không cần 'mintty', vì bạn không muốn thiết bị đầu cuối - thay vì trực tiếp gọi' bash.exe' của bạn. –

+0

bài đăng gốc đã được chỉnh sửa! Tôi cũng không hiểu cách trả lời nhận xét hoạt động trong 'StackOverflow' –

1

Bạn không cần Cygwin đây. Có một số thư viện Java thuần túy triển khai giao thức SSH. Sử dụng chúng. BTW họ sẽ giải quyết vấn đề thứ hai của bạn. Bạn sẽ mở phiên làm việc và thực thi lệnh với cùng một phiên, vì vậy trạng thái trình bao sẽ được bảo toàn tự động.

Một ví dụ sẽ là JSch.

+0

SSH sẽ không giúp thực thi các lệnh shell của Unix trên một cửa sổ. –

+0

javadocs của jsch không hoạt động và tôi không thể tìm ra các phụ thuộc. bạn có thể giúp tôi? những gì xảy ra trong tệp pom.xml của tôi? –

+0

@ Martin: JSch không phải là một mô phỏng unix trong Java, nó là một thực thi SSH client. Bạn có thể sử dụng điều này để kết nối với một máy chủ (thường là một máy tính khác) mà sau đó phải có một máy chủ SSH và một trình bao. –

Các vấn đề liên quan