2011-05-23 29 views
4

執行shell腳本有一個空的論點我的bash腳本,需要在幾個參數測試,然後和運行一個命令,如下圖所示從Java

call script => /bin/bash myscript arg1 arg2 arg3 arg4 
comm called => command -a arg1 -b arg2 -c arg3 -d arg4 

如果參數爲空,則該選項不可調用。

call script => /bin/bash myscript arg1 arg2 '' arg4 
comm called => command -a arg1 -b arg2 -d arg4 

我能夠通過使用下面一行的腳本來測試參數

if test "${arg3:-t}" != "t" ; then 

這個腳本就像一個魅力的提示調用時實現這一目標。即使我用空白參數替換「」,它也能正常工作。

當我使用exec從java調用這個腳本時,這開始失敗。

Process p = Runtime.getRuntime().exec("/bin/bash myscript arg1 arg2 '' arg4"); 
expected command => command -a arg1 -b arg2 -d arg4 (as in above example) 
actual command => command -a arg1 -b arg2 -c '' -d arg4 

我不明白爲什麼會發生這種情況。哪裏有問題?在shell腳本中或者它的命令從java執行的方式?

這怎麼解決?

+0

「失敗」是什麼意思? – 2011-05-23 14:18:23

+0

可能重複[如何使用參數執行命令?](http://stackoverflow.com/questions/7134486/how-to-execute-command-with-parameters) – Raedwald 2015-01-07 20:32:22

回答

4

基本的問題是,java完全不想做任何事情來解析你給它的字符串,並將它很好地分解爲參數。

簡短的回答是使用String []版本的Runtime.exec:如果您有其他地方的參數解析比這更令人費解的

Runtime.getRuntime().exec(
    new String[] {"/bin/bash", "myscript", "arg1", "arg2", "", "arg4"}); 

,你可以通過字符串的解析關閉打壞,做:

Runtime.getRuntime().exec(
    new String[] {"/bin/bash", "-c", "/bin/bash myscript arg1 arg2 '' arg4"}); 

如果你要轉換的東西比那個在做複雜的重定向數量龐大像2>&1或建立整個管道,你可能需要這個bash -c伎倆。

編輯:

要明白是怎麼回事,你必須意識到,當用戶空間代碼告訴內核「與這些參數加載這個可執行文件,並開始處理的,說:」(*),什麼是傳遞給內核的是一個可執行文件,一個用於參數的字符串數組(這個參數數組的第0個/第1個元素是可執行文件的名稱,除了做一些奇怪的事情時),還有一個用於環境的字符串數組。當它看到此行

什麼bash所做的:

/bin/bash myscript arg1 arg2 '' arg4 

是想「好吧,/bin/bash不是內置,所以我的東西執行我們的使用放在一起參數數組的子我字符串解析算法,它知道報價和什麼「。擊然後確定該參數傳遞給內核的新工藝有:

  • /bin/bash

  • myscript

  • arg1

  • arg2

  • (空字符串)

  • arg4

現在bash有它適用於這裏相當複雜的字符串處理算法 - 它接受兩種不同的報價,當它發生外字符串或內雙引號它會做的$VAR擴張,它將用輸出替換反引號中的子命令等。

當您調用單字符串版本exec時,Java不會執行任何如此複雜的操作。它只是創建一個新的StringTokenizer並使用它來分解你給它的參數字符串。那個班不懂報價;它分裂該字符串成:

  • /bin/bash

  • myscript

  • arg1

  • arg2

  • ''(具有兩個字符,這兩者都是一個串單引號)

  • arg4

的Java然後調用String[]版本的exec。 (他們中的好,一個)

說明人們採摘尼特與此:

(*)是的,我故意eliding的差異之間的系統調用forkexecve。假裝他們現在只是一個電話。

+0

@ Daniel謝謝。第一個建議很好。任何想法這兩種方法有什麼區別?我認爲java只是簡單地使用提供的字符串來完成這個過程,因此相同的字符串也可以從exec中運行。 – 2011-05-23 17:34:02

+0

@Salman發生的事情非常複雜,我無法在這裏的評論中充分解釋它。簡短的版本是在低層次上,進程總是由一個字符串數組產生,無論是java和bash。當我有空閒時,我會在上面的答案中添加更多細節。 – 2011-05-24 22:03:58

0

您不應該使用Runtime.exec。 Java 5引入了您應該使用的ProcessBuilder。它使您可以更好地控制啓動過程和設置環境。

ProcessBuilder pb = new ProcessBuilder("/bin/bash", "myscript", "arg1", "arg2", "", "arg4"); 
pb.start(); 
1

試試這個:

ProcessBuilder pb = new ProcessBuilder("/bin/bash", "myscript", "arg1", "arg2", "", "arg4"); 
Process proc = pb.start(); 
0

怎麼這樣呢?

javaParams="" 
[ -n "$1" ] && javaParams="-a '$1'" 
[ -n "$2" ] && javaParams="$javaParams -b '$2'" 
[ -n "$3" ] && javaParams="$javaParams -c '$3'" 
[ -n "$4" ] && javaParams="$javaParams -d '$4'" 
command $javaParams 

[ -n "$1" ] && javaParams="-a $1" 

相當於:

if [ -n "$1" ] 
then 
    javaParams="-a $1" 
fi 

-n試驗看到,如果提供的字符串的長度爲零或沒有。