Tham số hóa các cuộc gọi được kết nối tới một chương trình tiện ích ở Bash


12

Tôi có một chương trình UNIX hộp đen được sử dụng trong trình bao Bash đọc các cột dữ liệu từ stdin, xử lý chúng (áp dụng hiệu ứng làm mịn) sau đó xuất ra thiết bị xuất chuẩn. Tôi sử dụng nó bằng các ống UNIX, như

generate | smooth | plot  

Để làm mịn hơn, tôi có thể lặp lại độ mịn, do đó, nó sẽ được gọi từ dòng lệnh Bash như

generate | smooth | smooth | plot   

hoặc thậm chí

generate | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | plot

Điều này đang trở nên khó chịu. Tôi muốn tạo một trình bao bọc Bash để có thể kết nối smoothvà đưa đầu ra của nó trở lại vào một thể hiện mới của smoothmột số lần tùy ý, đại loại như

generate | newsmooth 5 | plot

thay vì

generate | smooth | smooth | smooth | smooth | smooth | plot

Nỗ lực đầu tiên của tôi là một tập lệnh Bash tạo các tệp tạm thời trong thư mục hiện tại và xóa chúng, nhưng nó trở nên xấu khi tôi không ở trong một thư mục có quyền truy cập ghi và cũng để lại các tệp rác khi bị gián đoạn.

Không có đối số cho smoothchương trình.

Có cách nào thanh lịch hơn để "bọc" một chương trình như vậy để tham số hóa số lượng cuộc gọi không?


1
Tôi hy vọng ví dụ của bạn là một trường hợp bắt buộc vì câu hỏi chứ không phải là nhu cầu thực tế
arielnmz

Câu trả lời:


18

Bạn có thể gói nó trong một hàm đệ quy:

smooth() {
  if [[ $1 -gt 1 ]]; then # add another call to function
    command smooth | smooth $(($1 - 1)) 
  else
    command smooth # no further 
  fi
}

Bạn sẽ sử dụng nó như là

generate | smooth 5 | plot

tương đương với

generate | smooth | smooth | smooth | smooth | smooth | plot

Điều này là hoàn hảo, hành xử chính xác như cần thiết. Và bây giờ tôi đã học về từ khóa "lệnh" bash.
Diane Wilbor

2
Ngẫu nhiên, đây là cách tiếp cận tương tự mà tôi sử dụng trong Làm cách nào để mã hóa một chuỗi ống dài tùy ý? - và, rất lâu trước đó, trong việc xử lý danh sách chỉnh sửa dài trong xmlstarlet .
Charles Duffy

5

Nếu bạn có thể đủ khả năng để nhập nhiều dấu phẩy như số lượng smooth lệnh bạn muốn, bạn có thể tận dụng lợi thế của Mở rộng Brace được phân tách bằng dấu phẩy.

TL; DR

Toàn bộ dòng lệnh cho trường hợp mẫu của bạn sẽ là:

generate | eval 'smooth |'{,,,,} plot

Ghi chú:

  • thêm hoặc xóa dấu phẩy nếu bạn muốn lặp lại nhiều hơn hoặc ít hơn smooth |
  • không có |trước đây plotbởi vì điều đó được bao gồm trong cuối cùngsmooth | chuỗi được sản xuất bởi Brace Expansion
  • bạn cũng có thể cung cấp các đối số smooth, miễn là bạn có thể đưa chúng vào chính xác trong phần cố định được trích dẫn trước dấu ngoặc mở; trong mọi trường hợp hãy nhớ rằng bạn sẽ cung cấp cho họ tất cả các lần lặp lại của lệnh

Làm thế nào nó hoạt động

Mở rộng Brace được phân tách bằng dấu phẩy cho phép bạn tự động tạo ra các chuỗi, mỗi chuỗi được tạo từ một phần cố định được chỉ định cộng với các phần biến được chỉ định. Nó tạo ra nhiều chuỗi như có các phần thay đổi được chỉ định, nhưa{b,c,d} sản xuất ab ac ad.

Một mẹo nhỏ ở đây là nếu bạn muốn tạo một danh sách các phần biến rỗng , tức là chỉ có dấu phẩy bên trong dấu ngoặc, Mở rộng Brace sẽ chỉ tạo ra các bản sao của phần cố định. Ví dụ:

smooth{,,,,}

sẽ sản xuất:

smooth smooth smooth smooth smooth

Lưu ý rằng 4 dấu phẩy tạo ra 5smooth chuỗi. Đó chỉ là cách hoạt động của Brace Expansion này: nó tạo ra nhiều chuỗi dấu phẩy cộng với một.

Tất nhiên trong trường hợp của bạn, bạn cũng cần |tách riêng từng phần smooth, vì vậy chỉ cần thêm nó vào phần cố định nhưng hãy cẩn thận để trích dẫn nó đúng cách để vỏ không giải thích nó ngay lập tức. Đó là:

'smooth|'{,,,,}

sẽ sản xuất:

'smooth|' 'smooth|' 'smooth|' 'smooth|' 'smooth|'

Cẩn thận luôn đặt phần cố định ngay lập tức liền kề với nẹp mở, tức là không có khoảng cách giữa ' và {.

(Cũng lưu ý rằng để tạo thành phần cố định, bạn cũng có thể sử dụng dấu ngoặc kép thay vì dấu ngoặc đơn, nếu bạn cần mở rộng các biến shell trong phần cố định. bên trong một chuỗi trích dẫn kép).

Tại thời điểm này bạn cần một eval  ứng dụng cho chuỗi đó để làm cho shell cuối cùng diễn giải nó như là lệnh pipelined mà nó được cho là.

Do đó, để tổng hợp tất cả, toàn bộ dòng lệnh cho trường hợp mẫu của bạn sẽ là:

generate | eval 'smooth |'{,,,,} plot

1
Có những lo ngại bảo mật đáng kể nếu điều này được sử dụng ở những nơi mà cuộc gọi được tham số hóa. Xem câu trả lời của tôi về chức năng bash đệ quy so với xây dựng chuỗi lặp evalal eval: chuỗi nào hoạt động tốt hơn? trên Stack Overflow.
Charles Duffy

1
@CharlesDuffy Tôi hoàn toàn đồng ý với những lo ngại của bạn về các rủi ro tiềm ẩn evalkhi sử dụng khi cung cấp chuỗi không tin cậy, không vệ sinh, để đánh giá, đó là khi được sử dụng với các biến có thể mang nội dung "không xác định" như trường hợp bạn liên kết. Mặt khác, evalcũng có thể rất thuận tiện cho việc "sửa ống nước" nhanh chóng, đặc biệt là khi được sử dụng tại dấu nhắc, giống như trường hợp trong tay, trong đó evalđầu vào sẽ chỉ là một chuỗi ký tự được người dùng gõ vào người
LL3

Như đã thấy ở nơi khác, bạn luôn có thể thay thế eval strbằng một cái gì đó tự phụ & ngu ngốc như thế . /dev/stdin <<<str. Điều này không chỉ tạo ấn tượng với những kẻ ngốc, mà còn khiến @CharlesDuffy rời khỏi lưng bạn ;-)
pizdelect

1
@pizdelect, bạn có thể đọc bình luận trước của LL3 một cách cẩn thận - nó cân bằng, sắc thái và khôn ngoan. (Thật vậy, nhận xét ban đầu của riêng tôi có những sắc thái mà bạn dường như đang bỏ qua; "nếu được sử dụng trong trường hợp cuộc gọi được tham số hóa" là một điểm khác biệt quan trọng: trường hợp của LL3 không được tham số hóa, làm cho nó an toàn).
Charles Duffy
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.