tìm: thiếu đối số cho -exec


18

Tôi đang cố chạy lệnh sau:

find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' +

Điều này đang trả về một lỗi:

find: missing argument to -exec

Tôi không thể thấy có gì sai với lệnh này, vì nó dường như khớp với trang man:

lệnh -exec {} +

Biến thể này của tùy chọn -exec chạy lệnh được chỉ định trên các tệp đã chọn, nhưng dòng lệnh được tạo bằng cách nối thêm từng tên tệp đã chọn ở cuối; tổng số lượng yêu cầu của lệnh sẽ ít hơn nhiều so với số lượng tệp được khớp. Dòng lệnh được xây dựng theo cách tương tự như xargs xây dựng các dòng lệnh của nó. Chỉ một trường hợp '{}' được cho phép trong lệnh. Lệnh được thực thi trong thư mục bắt đầu.

Tôi cũng đã thử:

find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar {} +
find a/folder b/folder -name *.c -o -name *.h -exec 'grep -I foobar' {} +
find a/folder b/folder -name *.c -o -name *.h -exec 'grep -I foobar' '{}' +
find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar '{}' +
find a/folder b/folder \( -name *.c -o -name *.h \) -exec grep -I foobar '{}' +
find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+

Bạn đã cố gắng thoát khỏi +cuối? find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+
jayhendren

3
Bạn có thể đang sử dụng một phiên bản cũ của GNU find. Mặc dù -exec cmd {} +biến thể là POSIX và đã có sẵn từ những năm 80, GNU tìm thấy chỉ thêm nó (tương đối) gần đây (2005). Điều gì find --versionnói với bạn?
Stéphane Chazelas

2
@Koveras, đó sẽ là nó sau đó. -exec {} +đã được thêm vào 4.2.12 vào năm 2005. Trong các phát hiện GNU cũ hơn, bạn có thể sử dụng (không phải POSIX) -print0 | xargs -r0để có được thứ gì đó tương tự. 4.1là từ năm 1994.
Stéphane Chazelas

1
JRFerguson đã chỉ ra (trong một câu trả lời đã bị xóa) rằng các -nameđối số mẫu nên được trích dẫn : -name "*.c" -o -name "*.h". Điều này là đúng, mặc dù nó không liên quan đến -execlỗi. Bạn sẽ nhận thấy rằng tất cả các câu trả lời khác đều đặt các ký tự đại diện vào dấu ngoặc kép, mặc dù chỉ Gilles đề cập đến nó. Tiết (Cont'd)
G-Man nói 'Tái lập lại Monica'

1
(Tiếp theo) Câu trả lời của jlliagre thu gọn biểu thức tên -name "*.[ch]"mà không cần giải thích. Điều này có lợi ích của việc đơn giản hóa dòng lệnh và đặc biệt là loại bỏ  -o. Tìm biểu thức liên quan -olà khó để có được đúng. Bạn sai rồi; nếu lệnh của bạn được sửa để nó không bị lỗi (như trong câu trả lời của Gilles), nó sẽ grepchỉ chạy trên các .htệp. Bạn cần phải làm '(' -name '*.c' -o -name '*.h' ')'.
G-Man nói 'Phục hồi Monica'

Câu trả lời:


18

Bạn cần loại bỏ các trích dẫn duy nhất bạn sử dụng xung quanh {}. Lệnh có thể được đơn giản hóa như thế này:

find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} +

Nếu bạn sử dụng phiên bản tìm kiếm GNU cổ xưa, phiên bản này vẫn hoạt động:

find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} \;

Rất tiếc, chúng có nghĩa là trích dẫn không backticks.
David Kennedy

Trích dẫn sẽ là vô ích vì {}không có ý nghĩa cụ thể cho vỏ.
jlliagre

Từ trang tìm kiếm: "Chuỗi '{}' được thay thế bằng tên tệp hiện tại đang được xử lý ở mọi nơi, nó xuất hiện trong các đối số cho lệnh, không chỉ trong các đối số chỉ có một mình, như trong một số phiên bản tìm thấy. các công trình có thể cần phải được thoát ra (với '\') hoặc được trích dẫn để bảo vệ chúng khỏi sự mở rộng của vỏ. "
David Kennedy

1
Tôi thực sự đã đọc nó trong trang hướng dẫn nhưng thực tế là không có vỏ tôi biết rằng cần phải trích dẫn các dấu ngoặc nhọn. Bạn đang sử dụng vỏ gì?
jlliagre

bash. Có hoặc không có dấu ngoặc kép tôi vẫn nhận được lỗi.
David Kennedy

10

Đối số bị thiếu đối với người -execViking thường có nghĩa là đối số đến - execđang thiếu dấu chấm dứt của nó. Dấu kết thúc phải là một đối số chỉ chứa ký tự ;(cần được trích dẫn trong lệnh shell, do đó, nó thường được viết \;hoặc ';') hoặc hai đối số liên tiếp chứa {}+ .

Stephane Chazelas đã xác định rằng bạn đang sử dụng một phiên bản cũ của GNU tìm mà không hỗ trợ -exec … {} +, chỉ -exec {} \;. Mặc dù GNU là người chấp nhận muộn -exec … {} +, nhưng tôi khuyên bạn nên có một bộ công cụ ít cổ hơn (như Cygwin , bao gồm git và nhiều thứ khác, hoặc GNUwin32 , thiếu git nhưng không có nhân viên xấu cố gắng -to-use-linux-but-we-impose-windows rung cảm mà Cygwin đưa ra). Tính năng này đã được thêm vào trong phiên bản 4.2.12, hơn 9 năm trước (đây là tính năng được xác định cuối cùng để làm cho GNU findPOSIX tuân thủ).

Nếu bạn muốn dính vào một GNU find cũ hơn, bạn có thể sử dụng -print0với xargs -0để có được một chức năng tương tự: nhóm thực hiện lệnh, hỗ trợ tên tập tin tùy ý.

find a/folder b/folder -name '*.c' -o -name '*.h' -print0 | xargs -0 grep -I foobar /dev/null

Luôn trích dẫn các ký tự đại diện trên finddòng lệnh. Mặt khác, nếu bạn tình cờ chạy lệnh này từ một thư mục chứa .ccác tệp, phần không trích dẫn *.csẽ được mở rộng thành danh sách các .ctệp trong thư mục hiện tại.

Thêm /dev/nullvào grepdòng lệnh là một mẹo để đảm bảo rằng grep sẽ luôn in tên tệp, ngay cả khi findtình cờ tìm thấy một kết quả khớp duy nhất. Với GNU find, một phương thức khác là truyền tùy chọn -H.


1
Bạn có ý nghĩa gì với sự rung cảm của nhân viên tồi cố gắng sử dụng linux-but-we-impose-windows mà cygwin mang lại?
David Kennedy

GNUwin32 không mong đợi :(
David Kennedy

Xem bình luận của tôi về câu hỏi.
G-Man nói 'Phục hồi Monica'

Các trích dẫn xung quanh semi đã hoạt động từ trong một script script.json.
bvj

2

Nếu một lệnh như

find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar {} +

trả về lỗi

find: missing argument to -exec

nguyên nhân có thể xảy ra là GNU quá cũ findkhông hỗ trợ cú pháp -exec mycommand {} +. Trong trường hợp đó, thay thế hiệu suất thấp là chạy -exec mycommand {} \;sẽ chạy mycommandmột lần cho mỗi mục tiêu tìm thấy thay vì thu thập nhiều mục tiêu và chỉ chạy mycommandmột lần.

Tuy nhiên, GNU findkhông hỗ trợ, vd

find . -type f -and -name "*.ttf" -exec cp {} ~/.fonts +

bởi vì GNU findchỉ hỗ trợ kết hợp theo nghĩa đen {} +thay vì chung chung hơn {} additional parameters +. Lưu ý rằng không thể có bất cứ điều gì giữa niềng răng và +nhân vật. Nếu bạn thử điều này, bạn sẽ nhận được cùng một lỗi:

find: missing argument to -exec

Cách giải quyết là sử dụng cú pháp {} additional parameters \;hoạt động nhưng sẽ thực thi lệnh một lần cho mỗi mục tiêu tìm thấy. Nếu bạn cần hiệu năng cao hơn với GNU, findbạn phải viết một tập lệnh trình bao bọc có thể nối thêm các tham số bổ sung cho các đối số đã cho. Cái gì đó như

#!/bin/bash
exec mycommand "$@" additional parameters

nên đủ tốt Hoặc, nếu bạn không muốn tạo tệp tạm thời, bạn có thể sử dụng một lớp để thay đổi thứ tự các tham số như thế này:

find . -type f -and -name "*.ttf" -exec bash -c 'mycommand "$@" extra arguments' {} +

Mà sẽ thực thi mycommand {list of ttf files} extra arguments. Lưu ý rằng bạn có thể cần phải nhân đôi các ký tự đặc biệt cho bash sau -ccờ.


(1) Phần trên thực sự trả lời câu hỏi đã được đưa ra bởi những người khác. (2) Những gì bạn đang mô tả không phải là một lỗ hổng hoặc thiếu sót trong GNU find, mà là hành vi đúng được chỉ định bởi POSIX .
G-Man nói 'Phục hồi Monica'

1
+1 Cuối cùng, ai đó trả lời tại sao các tham số bổ sung không hoạt động! Có vẻ như là một thiếu sót trong định nghĩa POSIX.
Jonathan

Nếu bạn có GNU, findcó lẽ bạn đã có GNU cp. Trong trường hợp này, bạn có thể find ... -exec cp --target-directory ~/.fonts {} +giữ {}phần cuối của chuỗi thực thi.
roaima

1

find . -type f -perm 0777 -exec chmod 644 {}\;

có lỗi find: missing argument to ``-exec' .

Thêm không gian giữa {}\cố định nó:

find . -type f -perm 0777 -print -exec chmod 644 {} \;


1
Không có vấn đề như vậy trong findlệnh trong câu hỏi trong tầm tay.
Kusalananda

Trong Câu hỏi, không phải vậy, tôi hiểu, nhưng vấn đề là "tìm: thiếu đối số với` `-exec '", vấn đề có thể xảy ra từ 2 lý do khác nhau, tôi đã trả lời vì tôi thấy cùng một tuyên bố vấn đề.
ShreePool

@Kusalananda rất đau buồn, noob đã cung cấp một giải pháp cho lỗi được báo cáo được OP nêu trong cả tiêu đề và nội dung của câu hỏi.
bvj

@bvj Câu hỏi liên quan rõ ràng với +hình thức của -exectùy chọn find. Câu trả lời này đang sửa một vấn đề mà người dùng đặt câu hỏi không có.
Kusalananda

-1

Tôi đã có những chia sẻ đau đầu với cú pháp exec trong quá khứ. hầu hết các ngày nay tôi thích cú pháp bash đẹp hơn:

for f in `find a/folder b/folder -name "*.[ch]"`; do grep -I foobar $f; done

Nó có một số hạn chế khi bạn muốn coi các tệp là một nhóm, vì mỗi tệp được đánh giá một cách an toàn, nhưng bạn có thể dẫn đầu ra ở nơi khác tốt


1
Mặc dù điều này có xu hướng hoạt động nhưng nó ít hữu ích hơn so với phiên bản tìm kiếm thuần túy vì nó không thể xử lý các tệp có khoảng trắng trong tên chính xác.
Etan Reisner

5
Không, đừng làm điều này. Điều này sẽ phá vỡ ngay khi các tập tin chứa khoảng trắng và các ký tự khác lạ của người Viking. Điều này cũng phức tạp hơn và chậm hơn find … -exec … \;, vì vậy không có lý do gì để sử dụng điều này ngay cả khi bạn biết rằng tên tệp của mình đã được thuần hóa.
Gilles 'SO- ngừng trở nên xấu xa'

điều này hữu ích cho trường hợp của tôi khi tôi cần chạy nhiều dòng logic dựa trên tên tệp (như xóa ký tự, tạo thư mục và sau đó di chuyển tệp). Cố gắng tìm kiếm để làm nhiều việc trong một execlà quá đau đầu trong 5 phút tôi muốn dành cho việc này. Tên tệp của tôi đã được thuần hóa và điều này đã giải quyết vấn đề của tôi :)
gMale
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.