Thao tác đường ống bash


9

Tôi đã đọc một số câu hỏi thao tác chuỗi bash đường ống khác nhưng chúng dường như là các ứng dụng chuyên biệt.

Về cơ bản, có cách nào để làm đơn giản hơn dưới đây?

thay vì

$ string='hello world'; string2="${string// /_}"; echo "${string2^^}"
HELLO_WORLD

cái gì đó như

$ echo 'hello world' | $"{-// /_}" | "${ -^^}"
HELLO_WORLD

Chỉnh sửa Tôi quan tâm đến việc duy trì các thao tác bash nếu có thể để duy trì tốc độ (trái ngược với sed / awk có xu hướng làm chậm rất nhiều kịch bản của tôi)

Chỉnh sửa2: @jimmij

Tôi thích ví dụ thứ hai và dẫn tôi đến việc thực hiện một chức năng.

bash_m() { { read x; echo "${x// /_}"; } | { read x; echo "${x^^}"; }; }
echo hello world | bash_m
HELLO_WORLD

1
Tại sao bạn nghĩ sed / awk sẽ chậm cho mục đích này? Họ nhanh như họ đến.
mkc

1
@Ketan Sed và awk là các quy trình riêng biệt, vì vậy chúng không bao giờ có thể nhanh như một thứ mà bash có thể thực hiện mà không cần khởi chạy một quy trình riêng biệt. Thông thường sự khác biệt này hầu như không đáng chú ý, nhưng trong đó vấn đề hiệu năng trong các kịch bản shell thường là một vòng lặp hoặc tính toán nhất định đang được lặp lại với số lượng rất lớn và sinh ra hàng ngàn quy trình sẽ chậm hơn đáng kể so với thao tác chuỗi đơn giản trong bash.
jw013

2
@ jw013 Điều này đúng với các chuỗi ngắn là "hello world" từ câu hỏi, nhưng nếu chuỗi quá dài, hãy nói trhướng dẫn sử dụng, thì ngược lại là đúng vì thời gian sinh ra các quy trình là không đáng kể so với thời gian thao tác chuỗi. sedawkđược dành riêng. Nếu chuỗi quá dài, hãy nói toàn bộ hướng dẫn sử dụng bash, sau đó bash chỉ có thể từ chối tiến hành hoàn toàn, vì một số hạn chế bên trong.
jimmij

2
@ jw013 Tôi tuyên bố đang chuỗi thao tác của bash đó là kém hiệu quả các công cụ sau đó dành riêng như sed, awk, trhoặc tương đương. Hãy xem câu trả lời của gena2x mà tôi đã chỉnh sửa trước đây để thêm chính xác thông tin này: unix.stackexchange.com/questions/162221/. Bạn có thể muốn so sánh nó với câu trả lời terdon cho cùng một câu hỏi mà anh ấy dành thời gian cho các chuỗi ngắn trong đó quá trình sinh sản mất nhiều thời gian nhất. Bạn có thể tự kiểm tra và đăng kết quả.
jimmij

1
@Miati Tại sao bạn nghĩ phần bổ sung read x; echo $xnày tốt hơn cho hiệu suất? Cú pháp trông không ngắn hơn hoặc sạch hơn. x=${x// /_}; x=${x^^}là một cách ngắn gọn hơn nhiều để làm điều tương tự như {read x; echo ${x.... Theo như hiệu suất, @jimmij đã chỉ ra rằng tr/ sedsẽ nhanh hơn bash, số ngã ba là bằng nhau. Sử dụng một đường ống luôn dẫn đến một quá trình bổ sung để đối số lưu một ngã ba không còn được áp dụng. Vì vậy, nếu đang sử dụng đường ống, chỉ cần sử dụng sed/ trvv Nếu bạn có thể làm điều đó trong bash, hãy làm như vậy và bỏ qua điều read x; echo $xvô nghĩa này .
jw013

Câu trả lời:


9

Những gì jimmij nói. Ví dụ cuối cùng của anh ấy là gần nhất bạn có thể nhận được những gì bạn đang cố gắng trong biểu thức đường ống của bạn.

Đây là một biến thể về chủ đề đó:

echo 'hello world'|echo $(read s;s=${s^^};echo ${s// /_})

Tôi có khuynh hướng sử dụng tr, vì nó khá nhanh.

echo 'hello world'|tr ' [:lower:]' '_[:upper:]'

Tôi cho rằng thật đáng tiếc khi bash không cho phép mở rộng tham số lồng nhau; OTOH, việc sử dụng các biểu thức lồng nhau như vậy có thể dễ dàng dẫn đến mã khó đọc. Trừ khi bạn thực sự cần mọi thứ để chạy nhanh nhất có thể, tốt hơn hết là viết mã dễ đọc, dễ hiểu và duy trì, thay vì mã trông thông minh là một PITA để gỡ lỗi. Và nếu bạn thực sự làm điều cần phải được thực hiện ở tốc độ tối đa bạn nên sử dụng mã biên dịch, không một kịch bản.


7

Bạn không thể vượt qua mở rộng tham số theo cách như vậy. Khi bạn đề cập đến xviệc sử dụng $biểu tượng như trong "${x}"biểu mẫu, thì đó phải là tên biến thực, không phải là đầu vào tiêu chuẩn, ít nhất là không phải trong bash. Trong zshbạn có thể thực hiện thay thế tham số lồng nhau theo cách sau:

$ x=''hello world'
$ echo ${${x// /_}:u}
HELLO_WORLD

(lưu ý: :uzshtương tự như ^^đối với bash)

Nesting in bash là không thể và tôi nghĩ những gì bạn viết trong câu hỏi là thứ tốt nhất có thể nhận được, nhưng nếu vì bất kỳ lý do kỳ lạ nào bạn cần liên quan đến các đường ống vào phương trình thì bạn có thể muốn thử điều này:

$ echo 'hello world' | { read x; echo "${x// /_}"; } | { read y; echo "${y^^}"; }
HELLO_WORLD

1
Xem xét cuộc trò chuyện gần đây của chúng tôi về cách tr/ sednhanh hơn so bashvới xử lý chuỗi và xem xét cách bạn đang sử dụng các đường ống để truyền chuỗi qua I / O tiêu chuẩn, tôi thấy không có nghĩa đen nào khi thực hiện các thao tác đó trong bash trái ngược với tr/ sed. Tại sao một người | { read x; echo $x... }lại trái ngược với | sedđiều đó làm điều tương tự?
jw013

1
@ jw013 thẳng thắn nói tôi thấy bên cạnh không có điểm. Đây chỉ là một ví dụ để buộc các đường ống vào vấn đề một cách mạnh mẽ, bởi vì OP rõ ràng đã yêu cầu họ và không muốn sử dụng các chương trình bên ngoài (cả hai echoreadđều được tích hợp sẵn, vì vậy về nguyên tắc nhanh hơn một chút). Như tôi đã viết trong câu trả lời các thao tác tham số lũy tiến mà OP có trong câu hỏi là cách tốt nhất có thể theo ý kiến ​​của tôi cho nhiệm vụ này trong bash. Dù sao vấn đề là khá hàn lâm.
jimmij
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.