Làm thế nào để sử dụng> trong một lệnh xargs?


160

Tôi muốn tìm một lệnh bash cho phép tôi grep mỗi tệp trong một thư mục và ghi đầu ra của grep đó vào một tệp riêng. Tôi đoán sẽ làm điều gì đó như thế này

ls -1 | xargs -I{} "grep ABC '{}' > '{}'.out"

nhưng, theo như tôi biết, xargs không thích dấu ngoặc kép. Tuy nhiên, nếu tôi loại bỏ dấu ngoặc kép, thì lệnh sẽ chuyển hướng đầu ra của toàn bộ lệnh thành một tệp có tên '{}'. Thay vì một loạt các tệp riêng lẻ.

Có ai biết một cách để làm điều này bằng cách sử dụng xargs? Tôi chỉ sử dụng kịch bản grep này làm ví dụ để minh họa vấn đề của mình với xargs vì vậy mọi giải pháp không sử dụng xargs đều không phù hợp với tôi.

Câu trả lời:


201

Đừng phạm sai lầm khi làm điều này:

sh -c "grep ABC {} > {}.out"

Điều này sẽ phá vỡ trong rất nhiều điều kiện, bao gồm tên tập tin vui nhộn và không thể trích dẫn đúng. Bạn {}phải luôn là một đối số hoàn toàn riêng biệt với lệnh để tránh lỗi tiêm mã. Những gì bạn cần làm là đây:

xargs -I{} sh -c 'grep ABC "$1" > "$1.out"' -- {}

Áp dụng cho xargscũng như find.

Nhân tiện, không bao giờ sử dụng xargs mà không có -0tùy chọn (trừ khi sử dụng tương tác một lần rất hiếm và có kiểm soát mà bạn không lo lắng về việc phá hủy dữ liệu của mình).

Cũng đừng phân tích ls. Không bao giờ. Sử dụng Globing hoặc findthay vào đó:http://mywiki.wooledge.org/ParsingLs

Sử dụng findcho mọi thứ cần đệ quy và một vòng lặp đơn giản với một quả cầu cho mọi thứ khác:

find /foo -exec sh -c 'grep "$1" > "$1.out"' -- {} \;

hoặc không đệ quy:

for file in *; do grep "$file" > "$file.out"; done

Chú ý sử dụng đúng dấu ngoặc kép.


Nâng cao nhưng một nghi ngờ regd. không sử dụng xargsmà không có -0: điều này chỉ áp dụng khi findđầu ra của bạn với xargs, phải không? Khi tôi làm xargs -a <input_file>thế nào tôi sẽ sử dụng này? Hầu hết các lệnh như grepkết quả đầu ra với \nvà không \0.Cách duy nhất tôi có thể nghĩ ra để làm việc xung quanh này là sử dụng trmột lần nữa để sửa chữa mà có lẽ. Nhưng tại sao nó chỉ quan trọng để sử dụng nó với -0?
huyền thoại2k

3
@ legends2k bởi vì khi bạn không sử dụng -0, xargssẽ lấy tên tệp của bạn và phá vỡ tất cả các khoảng trắng, dấu ngoặc kép và dấu gạch chéo ngược trong chúng. Bạn chỉ nên quên đi xargsnhư một công cụ. Nếu bạn có các dòng, hãy sử dụng vòng lặp bash để lặp lại các dòng: while read line; do <command> "$REPLY"; done < file-with-lineshoặccommand | while ...
lhunath

1
Wow, không biết về điều đó, cảm ơn vì chi tiết! Vì vậy, đối với tính di động (vì không phải tất cả xargsđều là GNU), xargscần phải tránh trừ khi người ta có thể sử dụng nó với -0. Cảm ơn bạn.
huyền thoại2k

1
Mặc dù tôi đánh giá cao lời giải thích chi tiết cho trường hợp sử dụng cụ thể này, câu hỏi là về việc chuyển hướng đầu ra của xargs, điều này không phải lúc nào cũng liên quan đến phân tích cú pháp lshoặc sử dụng sh -c. Điều này không trả lời câu hỏi một chút nào, nhưng là kết quả đầu tiên của google cho câu hỏi, chỉ làm tăng thêm sự nhầm lẫn.
pandasauce

1
@Ihunath, Xin chào, câu trả lời của bạn hoạt động tốt cho tôi. Nhưng bạn có thể đưa ra một số giải thích chi tiết hoặc liên kết về xargs -I{} sh -c 'grep ABC "$1" > "$1.out"' -- {}? Đặc biệt, các quy tắc của dấu ngoặc kép (dấu ngoặc kép) và ký hiệu "-" ở cuối. Cảm ơn bạn
Scott Yang

40

Một giải pháp mà không có xargsnhư sau:

find . -mindepth 1 -maxdepth 1 -type f -exec sh -c "grep ABC '{}' > '{}.out'" \;

... và điều tương tự có thể được thực hiện với xargs , hóa ra:

ls -1 | xargs -I {} sh -c "grep ABC '{}' > '{}.out'"

Chỉnh sửa : trích dẫn duy nhất được thêm sau khi nhận xét bởi lhunath .


Ông nói rằng ông muốn sử dụng xargs. Tôi đã đăng một giải pháp mà không có nó, nhưng đã xóa một khi tôi thấy rằng anh ta cần xargs.
Zifre

Bạn đúng. Lý do tôi đăng câu trả lời của mình là tốt hơn là nên có một giải pháp thay thế để hoàn thành công việc hơn là không có gì cả. Hóa ra nó đưa tôi đi đúng hướng để tìm câu trả lời mong muốn (đó là thủ thuật sh -c).
Stephan202

14

Tôi giả sử ví dụ của bạn chỉ là một ví dụ và bạn có thể cần> cho những thứ khác. GNU Parallel http://www.gnu.org/software/abul/ có thể là cứu cánh của bạn. Không cần trích dẫn bổ sung miễn là tên tệp của bạn không chứa \ n:

ls | parallel "grep ABC {} > {}.out"

Nếu bạn có tên tệp có \ n trong đó:

find . -print0 | parallel -0 "grep ABC {} > {}.out"

Là một phần thưởng bổ sung, bạn có được các công việc chạy song song.

Xem video giới thiệu để tìm hiểu thêm: http://pi.dk/1

Cài đặt 10 giây sẽ cố gắng thực hiện cài đặt đầy đủ; nếu thất bại, cài đặt cá nhân; Nếu thất bại, cài đặt tối thiểu:

$ (wget -O - pi.dk/3 || lynx -source pi.dk/3 || curl pi.dk/3/ || \
   fetch -o - http://pi.dk/3 ) > install.sh
$ sha1sum install.sh | grep 3374ec53bacb199b245af2dda86df6c9
12345678 3374ec53 bacb199b 245af2dd a86df6c9
$ md5sum install.sh | grep 029a9ac06e8b5bc6052eac57b2c3c9ca
029a9ac0 6e8b5bc6 052eac57 b2c3c9ca
$ sha512sum install.sh | grep f517006d9897747bed8a4694b1acba1b
40f53af6 9e20dae5 713ba06c f517006d 9897747b ed8a4694 b1acba1b 1464beb4
60055629 3f2356f3 3e9c4e3c 76e3f3af a9db4b32 bd33322b 975696fc e6b23cfb
$ bash install.sh

Nếu bạn cần di chuyển nó đến một máy chủ, không cài đặt GNU Parallel, hãy thử parallel --embed.

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.