xargs - nối từng đối số với một tham số


Câu trả lời:


12

Một cách để làm điều đó:

echo "a b c" | xargs printf -- '-f %s\n' | xargs mycommand

Điều này giả định a, bckhông chứa khoảng trống, dòng mới, dấu ngoặc kép hoặc dấu xồ nguợc. :)

Với GNU, findutilbạn có thể xử lý trường hợp chung, nhưng nó phức tạp hơn một chút:

echo -n "a|b|c" | tr \| \\0 | xargs -0 printf -- '-f\0%s\0' | xargs -0 mycommand

Bạn có thể thay thế các |dấu phân cách với một số nhân vật khác, điều đó không xuất hiện trong a, bhoặc c.

Chỉnh sửa: Như @MichaelMol lưu ý, với một danh sách các đối số rất dài, có nguy cơ vượt quá độ dài tối đa của các đối số có thể được chuyển qua mycommand. Khi điều đó xảy ra, cái cuối cùng xargssẽ phân chia danh sách và chạy một bản sao khác mycommand, và có nguy cơ nó sẽ bị hủy bỏ -f. Nếu bạn lo lắng về tình huống đó, bạn có thể thay thế cái cuối cùng xargs -0bằng một thứ như thế này:

... | xargs -x -0 mycommand

Điều này sẽ không giải quyết được vấn đề, nhưng nó sẽ hủy bỏ mycommandkhi danh sách các đối số quá dài.


1
Bạn có một rủi ro khá xấu là vượt quá ARG_MAXvà bị -ftách khỏi tham số được ghép nối của nó.
Michael Mol

@MichaelMol Đó là một điểm tốt, nhưng tôi không nghĩ có cách nào có ý nghĩa để xử lý tình huống đó mà không biết thêm mycommand. Bạn luôn có thể thêm -xvào cuối cùng xargs.
Satō Katsura

Tôi nghĩ rằng giải pháp thích hợp có lẽ là không sử dụng xargs, và chỉ sử dụng findnếu nó có thể được sử dụng. Giải pháp này là nguy hiểm; ít nhất bạn nên cảnh báo về trường hợp thất bại trong câu trả lời của bạn.
Michael Mol

@MichaelMol Tôi thực sự không thấy làm thế nào findsẽ là một giải pháp chung tốt hơn, đặc biệt khi các đối số ban đầu không có tên tệp. :)
Satō Katsura

Chúng tôi không biết những tranh luận ban đầu là gì; chúng ta chỉ thấy ví dụ đưa ra, không phải kịch bản đã truyền cảm hứng cho câu hỏi. Trực giác gợi ý rằng với một đối số có tên -fvà với một công cụ ví dụ lsđược sử dụng để minh họa, @ not-a-user đang xử lý tên tệp. Và đưa ra findcung cấp -execđối số, cho phép bạn xây dựng một dòng lệnh, nó ổn. (Miễn mycommandlà được phép thực thi nhiều lần. Nếu không, thì chúng ta có một vấn đề khác với việc sử dụng xargsở đây ...)
Michael Mol

5

Một cách tốt hơn để giải quyết nó (IMO) sẽ là:

  • trong zsh:

    l=(a b c)
    mycommand -f$^l

    hoặc sử dụng nén mảng để đối số không được đính kèm vào tùy chọn:

    l=(a b c) o=(-f)
    mycommand "${o:^^l}"

    Theo cách đó, nó vẫn hoạt động nếu lmảng chứa các phần tử trống hoặc phần tử chứa khoảng trắng hoặc bất kỳ ký tự có vấn đề nào khác xargs. Thí dụ:

    $ l=(a '' '"' 'x y' c) o=(-f)
    $ printf '<%s>\n' "${o:^^l}"
    <-f>
    <a>
    <-f>
    <>
    <-f>
    <">
    <-f>
    <x y>
    <-f>
    <c>
  • trong rc:

    l=(a b c)
    mycommand -f$l
  • trong fish:

    set l a b c
    mycommand -f$l

(AFAIK rcfishkhông có nén mảng)

Với các shell giống như Bourne kiểu cũ bash, bạn luôn có thể làm (vẫn cho phép bất kỳ ký tự nào trong các thành phần của $@mảng):

set -- a b c
for i do set -- "$@" -f "$i"; shift; done
mycommand "$@"

1
Một cách khác để làm điều đó trong bash là với một biến mảng được đặt tên. for i; do args+=('-f' "$i");done; mycommand "${args[@]}". IDK nếu điều này nhanh hơn, nhưng việc thêm 2 phần tử vào một mảng có vẻ như là O (n), trong khi setvòng lặp của bạn có thể sao chép và phân tích lại danh sách arg tích lũy mỗi lần (O (n ^ 2)).
Peter Cordes
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.