เราไม่เพียงแค่ grep เข้าไปใน ProcessBuilder

ไม่มีใครรู้วิธีใช้ linux grep กับ java ProcessBuilder หรือไม่ เหตุใดโค้ดนี้จึงส่งคืนสตริงว่างเมื่อควรส่งคืน "sing"

import java.io.*;
import java.util.*;

public class Test2 {

public static void main(String[] args) throws InterruptedException,IOException{
    String line;

    // Initiate grep process.
    ProcessBuilder pb = new ProcessBuilder("grep", "\"sing\"", "<<<\"sing\"");
    Process p = pb.start();
    p.waitFor();

    // Get grep output:     
    BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));

    StringBuilder builder = new StringBuilder();
    line = null;
    while ( (line = reader.readLine()) != null) {
        builder.append(line);
        builder.append(System.getProperty("line.separator"));
    }
    String result = builder.toString();
    System.out.println(result);     
}
}

ฉันยังพยายามสะท้อนสิ่งที่ฉันดำเนินการด้วยรหัสนี้:

ProcessBuilder pb = new ProcessBuilder("echo","grep", "\"sing\"", "<<<\"sing\"");

และรับผลลัพธ์ที่ถูกต้อง:

 grep "sing" <<<"sing"

ในที่สุดฉันก็พยายามรันคำสั่งที่เชลล์และได้รับ:

sing

แม้ว่าจะเป็นตัวอักษรสีแดงด้วยเหตุผลบางประการก็ตาม แล้วฉันทำอะไรผิดล่ะ?


person burnedWood    schedule 30.01.2015    source แหล่งที่มา
comment
ในตัวอย่างของคุณ grep กำลังรับหนึ่งอาร์กิวเมนต์ (ร้องเพลง) และสัญลักษณ์ <<< บอกให้เชลล์ส่งสิ่งใดก็ตามที่ตามมาเป็นสตรีมอินพุตไปยัง grep โค้ด ProcessBuilder ของคุณถือว่าสัญลักษณ์สตรีมอินพุตเป็นอาร์กิวเมนต์อื่น   -  person Brian    schedule 31.01.2015


คำตอบ (2)


ผมทำอะไรผิดหรือเปล่า?

บางสิ่งบางอย่างที่ค่อนข้างชัดเจน

คุณคาดหวังว่า execve() จะเข้าใจโครงสร้างเชลล์หรือไม่ เลขที่

คุณไม่ควรคาดหวังว่า ProcessBuilder จะเข้าใจสิ่งเหล่านั้นเช่นกัน แม้ว่าจะไม่ได้อยู่ในระดับต่ำเท่ากับ execve() แต่ก็อยู่ในระดับต่ำเพียงพอที่อาร์กิวเมนต์ของคำสั่งจะเป็น "ดิบ" ดังนั้น ในคำสั่งของคุณ <<<"sing" จะถูกส่งผ่านตามที่เป็นอยู่เป็นอาร์กิวเมนต์ไปยัง grep; ซึ่งหมายความว่า grep ดูเป็นไฟล์ที่จะอ่าน

คิดในใจ: สิ่งที่คุณพิมพ์ในเชลล์จะถูกตีความโดยเชลล์; ProcessBuilder จะไม่ ใช้เชลล์เพื่อดำเนินการกระบวนการของมัน และจะไม่ execve() ซึ่งในทางกลับกันหมายความว่าคุณ ไม่สามารถ ใช้โครงสร้างเชลล์ได้

หากคุณต้องการ grep คุณจะต้อง ป้อนข้อมูลกระบวนการของคุณ ด้วยข้อความที่คุณต้องการ แต่ทำไมต้องใช้ grep ในเมื่อ Java มีเอ็นจิ้น regex ในตัวนั้นเป็นอีกคำถามหนึ่งแน่นอน

As to:

แม้ว่าจะเป็นตัวอักษรสีแดงด้วยเหตุผลบางประการก็ตาม

มันเป็นเพียงการตกแต่งข้อความจากคำสั่ง grep (อย่างน้อย GNU grep); ดู manpage และตัวเลือก --color กล่าวโดยสรุป ในกรณีของคุณ ตรวจพบว่า tty ของคุณมีความสามารถในการเปลี่ยนสีของข้อความ และใช้สีนั้นในการตกแต่งข้อความที่ตรงกัน

ลองและ:

echo foobar | grep foo

มันจะสะท้อน foobar โดยมี foo เป็นสีแดง

person fge    schedule 30.01.2015
comment
สำหรับผู้ตอบแม้ว่าคุณจะโพสต์คำตอบที่ถูกต้อง คุณก็หยิ่งหรือหยาบคายโดยไม่จำเป็นต่อ OP โดยไม่สนใจความจริงที่ว่าสิ่งที่อาจดูเหมือนชัดเจนสำหรับคุณอาจเป็นปริศนาสำหรับผู้ถาม ถ้าเขารู้ แล้วจะถามไปทำไม? - person qualebs; 29.05.2017
comment
@qualebs ตกลงฉันเห็นด้วย ฉันสามารถเรียบเรียงคำตอบของฉันใหม่ได้ แต่สิ่งที่ทำให้ฉันตกใจก็คือนี่คือการเขียนโปรแกรมระบบปฏิบัติการ 101 ความละเอียดอ่อน (ไม่ใช่) ประเภทนี้ยังไม่ได้รับการสอนในหลักสูตรการเขียนโปรแกรมในปี 2560 ทำให้ฉันงุนงง - person fge; 29.05.2017

คุณสามารถรันคำสั่งเดียวกันได้โดยใช้ ProcessBuilder แต่คุณต้องแน่ใจว่าคำสั่งนั้นถูกรันโดย bash ฉันชอบวิธีอรรถประโยชน์นี้:

public static int runCmd(final String command) {
    Process process=null;
    int ret = 0;
    String[] finalCommand = new String[] { "bash", "-c", command };

    try {
        final ProcessBuilder processBuilder = new ProcessBuilder(finalCommand);
        processBuilder.redirectErrorStream(true);
        process = processBuilder.start();
        ret = process.waitFor();
        // stdout+stderr
        InputStreamReader isr = new InputStreamReader( process.getInputStream() );
        BufferedReader br = new BufferedReader(isr);
        String line;
        while ((line = br.readLine()) != null) {
          System.out.println(line);
        }
        //System.out.println("Program terminated!");
        process.destroy();
        br.close();
        isr.close();
    } 
    catch (IOException|InterruptedException e) { 
        e.printStackTrace(); 
    } 
    return ret;
}

แล้วเรียกมันว่า:

runCmd("grep -o \"sing\" <<<\"icansing\"");

และมันให้ผลลัพธ์:นี้แก่ฉัน

sing
person anubhava    schedule 30.01.2015
comment
แม้ว่าจะเป็นไปได้ แต่ก็แทบไม่เคยเป็นสิ่งที่ถูกต้องเลย มันอยู่ในระดับเดียวกับความเลวร้าย เหมือนกับระบบที่น่าอับอาย()... - person fge; 31.01.2015
comment
นั่นยังคงไม่หยุดโปรแกรมเมอร์ที่ใช้ system() และพูดตามตรงว่ามีบางกรณีที่ถูกต้องในการทำเช่นนั้น (ไม่ใช่ grep นี้) - person anubhava; 31.01.2015
comment
นั่นดูเหมือนเป็นวิธีที่มีประโยชน์ @fge สมมติว่าคุณอ้างถึงฟังก์ชัน C system() ทำไมมันถึงน่าอับอายขนาดนี้? ลิงก์ใดที่คุณอาจต้องการแบ่งปัน? - person burnedWood; 01.02.2015