Truyền nhiều tham số qua xargs


17

Tôi muốn có thể sử dụng xargsđể thực thi nhiều tham số trong các phần khác nhau của lệnh.

Ví dụ: như sau:

echo {1..8} | xargs -n2 | xargs -I v1 -I v2 echo the number v1 comes before v2

Tôi hy vọng nó sẽ trở lại

the number 1 comes before 2
the number 3 comes before 4 

... Vân vân

Điều này có thể đạt được? Tôi nghi ngờ rằng việc sử dụng nhiều lần của tôi -Ilà không chính xác.

Câu trả lời:


29

Tôi tin rằng bạn không thể sử dụng -Itheo cách đó. Nhưng bạn có thể có được hiệu ứng / hành vi bạn muốn bằng cách nói:

echo {1..8} | xargs -n2 sh -c 'echo "the number $1 comes before $2"' sh

Điều này, về cơ bản, tạo ra một kịch bản shell một dòng ad hoc , xargsthực thi thông qua sh -c. Hai giá trị xargsphân tích cú pháp ra khỏi đầu vào được truyền cho tập lệnh này. Shell sau đó gán các giá trị đó cho $1$2, sau đó bạn có thể tham chiếu trong tập lệnh script.


4
Cảm ơn bạn - điều đó thật tuyệt. Tôi đã đọc người đàn ông cho sh mặc dù và đang đấu tranh để hiểu cuộc gọi thứ hai với sh làm gì và, bằng cách mở rộng, tại sao thiếu sót của nó mang lại "một nửa" kết quả.
Damien Sawyer

6
@DamienSawyer Không có cuộc gọi thứ hai sh. Các dấu shở cuối là những gì được đưa vào $0. $0thường là những gì giữ tên của thông dịch viên hoặc kịch bản.
Kusalananda

Tôi chỉ thay thế dấu shvới echo $shmà nó hoạt động. Vì vậy, shchức năng cuối cùng là giữ chỗ
kenn

Chà, đó là sự đơn giản hóa những gì Kusalananda nói.
Scott

6

Trong trường hợp cụ thể printf, bạn luôn có thể làm:

echo {1..8} | xargs printf 'the number %s comes before %s\n'

bởi vì printfcó một xargskhả năng giống như nội tại để thực thi nhiều lần nếu nó được đưa ra nhiều đối số hơn mức cần thiết cho một lệnh gọi. Mặc dù điều đó có ít lợi thế hơn

printf 'the number %s comes before %s\n' {1..8}

Và đối với các danh sách lớn, xargslệnh đơn giản có thể dẫn đến việc xargschạy một số trường hợp printf, một số trong đó có thể có số lượng đối số lẻ. Bạn có thể vượt qua -n 1000để xargsbảo vệ chống lại điều đó, trong đó 1000 là một số chẵn đủ nhỏ để không đạt đến danh sách arg quá giới hạn quá dài và đủ lớn để tránh chạy quá nhiều printfs.

Lưu ý rằng xargssẽ gọi, không phải nội dung của shell của bạn printf, mà là bên ngoài printf, với mỗi lần gọi trong một quy trình mới riêng biệt.

Cũng lưu ý rằng đối với đầu vào trống, ngoại trừ một số BSD, nó vẫn sẽ chạy printfmột lần mà không có đối số. GNU xargsvà tương thích có một tùy chọn -r (hoặc --no-run-if-empty) để tránh điều đó.

Để rõ ràng, câu trả lời đơn giản này là cụ thể cho printfví dụ của bạn và sẽ không hoạt động trong trường hợp chung khi bạn phải truyền hai tham số cho lệnh của mình ( diffví dụ như trường hợp ). Để giải quyết vấn đề chung với zsh, bạn có thể sử dụng:

for i j ({1..8}) echo "the number $i comes before $j"

(1) IMHO, zshphần trên là một câu trả lời thực sự và phần xargs-with-no-Options chỉ là một sự kỳ quặc. Trong trường hợp như vậy, tôi sẽ xem xét đặt câu trả lời thực sự lên hàng đầu. (2) Tôi cho rằng bạn có lý do để không sử dụng dấu ngoặc kép trong zshlệnh của mình . Nếu vậy, bạn có thể muốn nói rõ, kẻo mọi người đọc những điều trên và bắt đầu nghĩ rằng trích dẫn không quan trọng. (Hoặc đơn giản chỉ bao gồm họ, vì họ không bị tổn thương.)
Scott

Điều này thực sự mát mẻ. Tôi đã đến đây để tìm kiếm một cái gì đó tương tự mà tôi không chắc chắn trước bao nhiêu cuộc tranh luận mà tôi sẽ nhận được phải được đưa vào dòng lệnh của cuộc tranh luận tiếp theo. đã làm một cái gì đó nhưawk -F'\t' '/match/{printf $1"\0"$2"\0"}' | xargs -0 printf -- '-args1 "%s" -args2 "%s"' | xargs mycommand
keithpjcar

@keithpjcar, việc sử dụng của bạn -0vào lần đầu tiên xargsđể làm cho nó đáng tin cậy hơn bị đánh bại bởi bạn không sử dụng nó vào lần thứ hai. Ngoài ra, các đối số đầu tiên printf(cả tiện ích độc lập và awk's printf()chức năng) là định dạng, bạn không nên sử dụng các biến đó. Ở đây, bạn có thể làm awk -F'\t' '/match/{printf "-args1\0%s\0-args2\0%s\0", $1, $2}' | xargs -n400 -r0 mycommand. Một lần nữa, -n400cần thiết để đảm bảo xargsvượt qua một số đối số là bội số của 4. (lưu ý rằng không phải tất cả các awktriển khai đều hỗ trợ sử dụng \0như thế ở đây).
Stéphane Chazelas

đã không sử dụng -0để làm cho nó đáng tin cậy hơn, sử dụng nó để làm cho nó làm những gì tôi muốn làm, điều đó làm.
keithpjcar

2

thử cái này:

echo {1..8} |xargs -n 2 bash -c 'echo "the number $0 comes before $1"'

2
Điều này sẽ hoạt động trong trường hợp này, nhưng tốt hơn là chạy sh -ctập lệnh có sh(hoặc bất cứ điều gì) trong $0. Lưu ý rằng $0không được bao gồm trong $@nếu điều này được sử dụng bởi sh -ctập lệnh, ví dụ nếu tập lệnh làecho "the two numbers were $@"
Kusalananda
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.