Làm thế nào để soạn các hàm bash bằng ống?


18

Tôi có một vài chức năng được định nghĩa theo kiểu này:

function f {
  read and process $1
  ...
  echo $result
}

Tôi muốn kết hợp chúng lại với nhau để lời mời sẽ như thế nào f | g | h.

Tôi sử dụng thành ngữ nào để chuyển đổi hàm làm việc trên các đối số thành một đối số đọc từ stdin? Có thể đọc các cặp, bộ đối số từ luồng mà không cần thoát chúng (ví dụ: kết thúc null) không?


Bạn muốn một cái gì đó giống như h(g(f(...)))hoặc từng hàm đọc từ đầu vào tiêu chuẩn ( read x; ...) và ghi vào đầu ra tiêu chuẩn ( echo ...).
vonbrand

Câu trả lời:


20

Một cách tiếp cận tiềm năng là đặt một while...readcấu trúc bên trong các chức năng của bạn để xử lý bất kỳ dữ liệu nào đi vào chức năng thông qua STDIN, vận hành trên nó và sau đó phát ra dữ liệu kết quả qua STDOUT.

function X {
  while read data; do
    ...process...
  done
}

Cần phải cẩn thận với cách bạn định cấu hình các while ..read..thành phần của mình vì chúng sẽ phụ thuộc nhiều vào loại dữ liệu mà chúng sẽ có thể tiêu thụ một cách đáng tin cậy. Có thể có một cấu hình tối ưu mà bạn có thể đưa ra.

Thí dụ

$ logF() { while read data; do echo "[F:$(date +"%D %T")] $data"; done; }
$ logG() { while read data; do echo "G:$data";                    done; }
$ logH() { while read data; do echo "H:$data";                    done; }

Đây là mỗi chức năng của chính nó.

$ echo "hi" | logF
[F:02/07/14 20:01:11] hi

$ echo "hi" | logG
G:hi

$ echo "hi" | logH
H:hi

Chúng ở đây khi chúng ta sử dụng chúng cùng nhau.

$ echo "hi" | logF | logG | logH
H:G:[F:02/07/14 19:58:18] hi

$ echo -e "hi\nbye" | logF | logG | logH
H:G:[F:02/07/14 19:58:22] hi
H:G:[F:02/07/14 19:58:22] bye

Họ có thể có nhiều phong cách đầu vào.

#-- ex. #1
$ cat <<<"some string of nonsense" | logF | logG | logH
H:G:[F:02/07/14 20:03:47] some string of nonsense

#-- ex. #2    
$ (logF | logG | logH) <<<"Here comes another string."
H:G:[F:02/07/14 20:04:46] Here comes another string.

#-- ex. #3
$ (logF | logG | logH)
Look I can even
H:G:[F:02/07/14 20:05:19] Look I can even
type to it
H:G:[F:02/07/14 20:05:23] type to it
live
H:G:[F:02/07/14 20:05:25] live
via STDIN
H:G:[F:02/07/14 20:05:29] via STDIN
..type Ctrl + D to stop..

#-- ex. #4
$ seq 5 | logF | logG | logH
H:G:[F:02/07/14 20:07:40] 1
H:G:[F:02/07/14 20:07:40] 2
H:G:[F:02/07/14 20:07:40] 3
H:G:[F:02/07/14 20:07:40] 4
H:G:[F:02/07/14 20:07:40] 5

#-- ex. #5
$ (logF | logG | logH) < <(seq 2)
H:G:[F:02/07/14 20:15:17] 1
H:G:[F:02/07/14 20:15:17] 2

4

Là một phụ lục cho câu trả lời của slm , tôi đã thực hiện một số thử nghiệm với các bộ dữ liệu được phân tách bằng null làm đối số hàm:

$ sayTuple() { 
    IFS= read -r -d $'\0' d1
    IFS= read -r -d $'\0' d2
    echo "sayTuple: -$d1- -$d2-"
}

Ghi chú: sayTuplehai lần đọc một bản ghi kết thúc null -d $'\0'xử lý bất kỳ khoảng trống nào xung quanh đầu vào IFS=. echohồ sơ trở lại bao quanh bởi-

Kết quả cho thấy nó xử lý chính xác đầu vào kết thúc null có chứa \n\t:

$ printf "%s\0%s\0" "Hello " $' Brave\n\tWorld' | sayTuple 
sayTuple: -Hello - - Brave
        World-

Vui lòng thêm đề xuất để cải thiện ý kiến, đó là một chủ đề thú vị.


+1 như ý tưởng của bạn. Chúng ta có thể đặt một vòng lặp bên trong thay vào đó sẽ cho phép nó lấy các đối số tùy ý. sayTuple() { arr=() ; while IFS= read -r -d $'\0' arg; do arr+="$arg"; done; echo "sayTuple: ${arr[@]}"; }.
slm

Có vẻ như bạn sẽ có thể làm một IFS= read -r -d $'\0' -a argnhưng tôi không thể làm điều này để làm việc. Điều này sẽ cho phép loại bỏ whilecái có vẻ không cần thiết, nhưng là mẫu duy nhất tôi có thể làm việc.
slm
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.