Cách đưa ra một danh sách được phân tách bằng dấu phẩy làm đối số cho lệnh tiếp theo


9

Tôi có một tập lệnh s1xuất ra danh sách các số được phân tách bằng ',' ví dụ 1,2,3,4. Bây giờ tôi muốn đưa các số này vào tập lệnh s2dưới dạng đối số, để s2 sẽ được chạy trên mỗi số đó và đưa ra kết quả của nó trong một dòng riêng biệt. Ví dụ: nếu s2 nhân số nhân với hai, đây sẽ là kết quả tôi đang tìm kiếm:

2
4
6
8

Những gì tôi đang làm bây giờ là:

s1 | xargs -d "," | xargs -n1 s2

Nhưng tôi cảm thấy như mình đang làm điều đó một cách ngu ngốc! Vì vậy, câu hỏi của tôi là:

Cách thích hợp để làm điều đó là gì?

Vấn đề của tôi với giải pháp của tôi là nó gọi xargs hai lần và lặp lại hai lần đầu vào, điều này không hợp lý với mắt tôi tất nhiên là bằng hiệu suất! Câu trả lời xargs -d "," -n1có vẻ hay, nhưng tôi không chắc nếu nó chỉ lặp lại một lần. Nếu có, vui lòng xác minh rằng trong câu trả lời của bạn và tôi sẽ chấp nhận nó. Nhân tiện, tôi không muốn sử dụng Perl vì nó vẫn lặp lại hai lần và Perl có thể không tồn tại trên nhiều hệ thống.


1
Nếu nó hoạt động tại sao gọi nó là ngu ngốc. Nếu thời gian thực hiện là quan trọng thì đó là một vấn đề khác rời khỏi đây
George Udosen

2
Hãy thử điều nàys1 | xargs -d "," -n1 s2
George Udosen

1
Tôi nghi ngờ một số vấn đề là hiểu sai về tác động của việc lặp lại. Lặp lại các yếu tố trong một cái gì đó như một mảng kết hợp là xấu vì chi phí cho việc đi bộ cấu trúc dữ liệu đó, nhưng nói chung "lặp lại" không phải là xấu. Cụ thể, đọc từng dòng dữ liệu khi xuất hiện trên STDIN, không phải là một vấn đề lớn về hiệu suất. Vấn đề hiệu suất ở đây là chi phí sinh ra một quy trình mới và thiết lập đường ống dẫn. Miễn là bạn không làm điều đó thường xuyên (như trong một vòng lặp), lo lắng về hiệu suất của xargs có lẽ là một ví dụ về tối ưu hóa sớm.
dannysauer

Câu trả lời:


18

Điều này cũng sẽ làm việc như nhau:

s1 | xargs -d "," -n1 s2

Trường hợp thử nghiệm:

printf 1,2,3,4 | xargs -d ',' -n1 echo

Kết quả:

1
2
3
4

Nếu s1đầu ra danh sách được theo sau bởi một ký tự dòng mới, bạn muốn xóa nó nếu không thì cuộc gọi cuối cùng sẽ 4\nthay vì 4:

s1 | tr -d '\n' | xargs -d , -n1 s2

6

Nếu s2có thể chấp nhận nhiều đối số, bạn có thể làm:

(IFS=,; ./s2 $(./s1))

tạm thời ghi đè IFS thành dấu phẩy, tất cả nằm trong một ô con, để s2thấy đầu ra s1bị phá vỡ bởi dấu phẩy. Subshell là một cách ngắn gọn để thay đổi IFS mà không lưu giá trị trước đó hoặc đặt lại nó.

Phiên bản trước của câu trả lời này không chính xác, có thể là do cài đặt IFS còn sót lại, làm hỏng kết quả. Nhờ ilkkachu cho chỉ ra sai lầm của tôi .

Để lặp lại thủ công các đầu ra và cung cấp chúng riêng lẻ s2, ở đây thể hiện việc lưu và đặt lại IFS:

oIFS="$IFS"
IFS=,
for output in $(./s1); do ./s2 "$output"; done
IFS="$oIFS"

hoặc chạy các bit IFS trong một khung con như trước:

(
IFS=,
for output in $(./s1); do ./s2 "$output"; done
)

1
Bạn có chắc chắn về điều đó đầu tiên? bash -c 'IFS=, printf "%s\n" $(echo 1,2,3)'in 1,2,3trên hệ thống của tôi, tức là không có sự phân tách.
ilkkachu

Tôi sẽ kiểm tra lại một chút, nhưng tôi nghi ngờ hành vi khác nhau dựa trên nội dung so với chương trình bên ngoài.
Jeff Schaller

cùng với /usr/bin/printf/bin/echo
ilkkachu

1
@ilkkachu Bạn đã đúng, việc tách từ xảy ra trước khi IFS được gán lại trong trường hợp này (IFS=,; printf "%s\n" $(echo 1,2,3)), mặt khác, sẽ hoạt động.
undercat hoan nghênh Monica

1

Thử cái này:

s1 | perl -pe 's/,/\n/g' | xargs -n1 s2


3
Tại sao không đơn giản tr ',' '\n'? Không cần phải gọi một cái gì đó (tương đối) nặng như Perl và các biểu thức thông thường.
David Foerster
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.