DEV Community

loading...

เขียนโปรแกรมล้อ pipe ใน shell script

Vee Satayamas
Free software developer
・1 min read

5 มีนาคม 2562

ใน shell script มัน pipe ต่อกันไปได้เรื่อย ๆ แบบนี้

cat input.txt | \
      prog1 x | \
      prog2 y | \
      prog3 z
Enter fullscreen mode Exit fullscreen mode
  • cat อ่านไฟล์ input1.txt แล้วก็ส่งออกมาทาง stdout ต่อมาก็ส่งเข้า prog1 ทาง stdin
  • prog1 อ่านข้อมูลจาก stdin ที่ cat ส่งมา; แล้วประมวลผลแล้วก็ส่งออกไป stdout
  • prog2 อ่านข้อมูลจาก stdin ที่ prog1 ส่งมา; แล้วประมวลผลแล้วก็ส่งออกไป stdout
  • prog3 อ่านข้อมูลจาก stdin ที่ prog2 ส่งมา; แล้วประมวลผลแล้วก็ส่งออกไป stdout
  • โดยที่ prog1 prog2 prog3 ก็รับค่า x y z เข้ามาทาง argument ด้วย

โปรแกรมแบบนี้จะเขียนใหม่เป็น Ruby ก็จะได้ประมาณนี้ หรือจะใช้ Java ก็จะคล้าย ๆ กัน

p read_file("input.txt").prog1(:x)
    .prog2(:y)
    .prog3(:z)
Enter fullscreen mode Exit fullscreen mode

พวก prog1 prog2 prog3 กลายเป็นชื่อ method ใน object ที่ดูจาก code ก็ไม่รู้ว่า object อะไร หรือกระทั่งตอนรันก็ไม่รู้ว่า prog1 ส่งข้อมูลอะไรออกมา

ถ้าเป็น shell script ก็ใส่ tee เข้าไปได้เลย

cat input.txt | \
      prog1 x | \
      prog2 y | \
      tee debug.txt | \
      prog3 z
Enter fullscreen mode Exit fullscreen mode

แล้วก็ไปเปิดดูไฟล์ debug.txt ทีหลังได้ โดยที่โปรแกรมโดยรวมก็ยังทำงานปกติ

แต่ถ้าเป็น Ruby หรือ Java ก็จะกลายเป็นท่ายาก เพราะว่าใส่ tee เข้าไปใน object ก็ยากเพราะไม่รู้ว่า object ไหน class อะไร ใส่ไปแล้วจะมั่วหรือเปล่า

โปรแกรมมันก็จะออกมาประมาณนี้แทน

tmp = read_file("input.txt").prog1(:x)
        .prog2(:y)
write_file(tmp)
p tmp.prog3(:z)
Enter fullscreen mode Exit fullscreen mode

ถ้าลองเปลี่ยนเป็น Clojure มันก็จะประมาณนี้

(-> (slurp "input.txt")
    (prog1 :x)
    (prog2 :y)
    (prog3 :z)
    println)
Enter fullscreen mode Exit fullscreen mode

พวก prog1 prog2 prog3 ก็จะเป็นแค่ function ธรรมดาแทนที่จะเป็น method

นอกจากนั้นก็ยังเขียน tee ขึ้นมาง่าย ๆ ได้แบบนี้

(defn tee [data path]
    (spit path data)
    data)
Enter fullscreen mode Exit fullscreen mode

แล้วก็เอา tee ไปแทรกได้แบบ shell script

(-> (slurp "input.txt")
    (prog1 :x)
    (prog2 :y)
    (tee "debug.txt")
    (prog3 :z)
    println)
Enter fullscreen mode Exit fullscreen mode

โปรแกรมทั้งหมดผมไม่ได้ลองรันจริง ๆ นะครับ อาจจะเจ๊งได้ จาก blog นี้ผมรู้สึกว่าตอบคำถามตัวเองได้ว่าทำไมเวลาเขียน Clojure หรือ Common Lisp ในโปรแกรมที่ค่อนข้างซับซ้อนแล้วรู้สึกสะดวกกว่า Ruby เอาจริงๆ จะเขียน Ruby หรือ Java ให้คล้าย ๆ Clojure ก็คงทำได้ แต่เขียนไปก็จะถูกเรียกว่าไม่ idiomatic อันนี้ก็เป็นอีกเหตุผลนึงให้เปลี่ยนภาษาเพราะว่าภาษามันพ่วงวัฒนธรรมมาด้วย

Discussion (0)