Sử dụng dấu chấm phẩy (;) so với dấu cộng (+) với exec trong find


159

Tại sao có sự khác biệt về đầu ra giữa việc sử dụng

find . -exec ls '{}' \+

find . -exec ls '{}' \;

Tôi đã nhận:

$ find . -exec ls  \{\} \+
./file1  ./file2

.:
file1  file2  testdir1

./testdir1:
testdir2

./testdir1/testdir2:


$ find . -exec ls  \{\} \;
file1  file2  testdir1
testdir2
./file2
./file1

Câu trả lời:


249

Điều này có thể được minh họa tốt nhất với một ví dụ. Hãy nói rằng findbật lên các tệp này:

file1
file2
file3

Sử dụng -execvới dấu chấm phẩy ( find . -exec ls '{}' \;), sẽ thực thi

ls file1
ls file2
ls file3

Nhưng nếu bạn sử dụng dấu cộng thay thế ( find . -exec ls '{}' \+), càng nhiều tên tệp càng tốt sẽ được chuyển dưới dạng đối số cho một lệnh:

ls file1 file2 file3

Số lượng tên tệp chỉ bị giới hạn bởi độ dài dòng lệnh tối đa của hệ thống. Nếu lệnh vượt quá độ dài này, lệnh sẽ được gọi nhiều lần.


1
cảm ơn. điều này rất hữu ích khi muốn sắp xếp các tệp kết quả: find -maxdepth 1 -type f -mtime -1 -exec ls -ltr {} \ +
fbas

1
Dumb q: Tôi nhận thấy rằng +liên kết với -execluôn luôn thoát, nhưng +liên kết với -mtimethì không. Bạn có biết lý do không? Tôi đoán đó là thói quen thoát khỏi ;liên quan đến -exec.
kevinarpe

3
@kevinarpe thực sự, tôi sẽ đánh bóng nó thành thói quen ;. Không thể tưởng tượng được là cần thiết phải trốn thoát+
Martin

36

Tất cả các câu trả lời cho đến nay là chính xác. Tôi cung cấp điều này như một minh chứng rõ ràng hơn (cho tôi) về hành vi được mô tả bằng cách sử dụng echochứ không phải ls:

Với dấu chấm phẩy, lệnh echođược gọi một lần cho mỗi tệp (hoặc đối tượng hệ thống tệp khác) được tìm thấy:

$ find . -name 'test*' -exec echo {} \;
./test.c
./test.cpp
./test.new
./test.php
./test.py
./test.sh

Với một dấu cộng, lệnh chỉ echođược gọi một lần. Mỗi tập tin tìm thấy được thông qua như là một đối số.

$ find . -name 'test*' -exec echo {} \+
./test.c ./test.cpp ./test.new ./test.php ./test.py ./test.sh

Nếu findbật lên số lượng lớn kết quả, bạn có thể thấy rằng lệnh được gọi là cuộn cảm về số lượng đối số.


1
Không nên tìm thêm kết quả chỉ vào một số làm cho an toàn để chuyển nó vào trình bao? Ít nhất là những gì xargslàm ... về nguyên tắc, nó không bao giờ bóp nghẹt vì quá nhiều tranh luận.
Rmano

1
@Rmano: Tôi đã thấy find(và xargs) trên Solaris phát ra nhiều tranh luận hơn mức có thể được tiêu thụ. Các xargs(và find) trong findutils` GNU của dường như cư xử hợp lý hơn, nhưng không phải ai cũng sử dụng GNU.
Johnsyweb

2
@Johnsyweb, tất cả POSIX findsẽ cố gắng tránh đạt đến giới hạn về số lượng đối số. Và bao gồm Solaris '(ít nhất 10). Trường hợp có thể thất bại là nếu bạn làm điều gì đó như find ... -exec ksh -c 'cmd "$@" "$@"' sh {} +hoặc find ... -exec ksh -c 'files="$*" cmd "$@"' sh {} +, nhưng findthực sự không thể đổ lỗi cho điều đó. Lưu ý rằng GNU findlà một trong những findtriển khai cuối cùng để hỗ trợ +(từng là một vấn đề khó khăn khi chuyển tập lệnh sang các hệ thống GNU).
Stephane Chazelas

18

Từ man find:

lệnh -exec;

Thực thi lệnh; đúng nếu trạng thái 0 được trả về. Tất cả các đối số sau đây cần tìm được coi là đối số của lệnh cho đến khi một đối số bao gồm ';' gặp phải 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 kiếm. Cả hai công trình này 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ỏ. Xem phần EXAMPLES sec để biết ví dụ về việc sử dụng tùy chọn '-exec'. Lệnh được chỉ định được chạy một lần cho mỗi tệp phù hợp. Lệnh được thực thi trong thư mục bắt đầu. Có những vấn đề bảo mật không thể tránh khỏi xung quanh việc sử dụng tùy chọn -exec;

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 xây dựng bằng cách nối thêm từng tên tệp đã chọn ở cuối ; tổng số lệnh gọi 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.

Vì vậy, theo cách tôi hiểu, \;thực thi một lệnh riêng cho mỗi tệp được tìm thấy find, trong khi \+nối thêm các tệp và thực thi một lệnh duy nhất trên tất cả chúng. Đây \là một nhân vật thoát, vì vậy nó:

ls testdir1; ls testdir2 

đấu với

ls testdir1 testdir2

Làm như trên trong vỏ của tôi nhân đôi đầu ra trong câu hỏi của bạn.

ví dụ về thời điểm bạn muốn sử dụng \+

Giả sử hai tệp 1.tmp2.tmp:

1.tmp:

1
2
3

2.tmp:

0
2
3

Với \;:

 find *.tmp -exec diff {} \;
> diff: missing operand after `1.tmp'
> diff: Try `diff --help' for more information.
> diff: missing operand after `2.tmp'
> diff: Try `diff --help' for more information.

Trong khi đó, nếu bạn sử dụng \+(để nối kết quả của find):

find *.tmp -exec diff {} \+
1c1,3
< 1
---
> 0
> 2
> 30

Vì vậy, trong trường hợp này, đó là sự khác biệt giữa diff 1.tmp; diff 2.tmpdiff 1.tmp 2.tmp

Có những trường hợp \;phù hợp và \+sẽ cần thiết. Sử dụng \+với rmlà một ví dụ như vậy, trong đó nếu bạn loại bỏ một số lượng lớn hiệu suất tệp (tốc độ) sẽ vượt trội hơn \;.


Tôi có thể đọc trang người đàn ông quá. Và tôi đã làm, nhưng tôi không nghĩ rằng tôi hiểu sự khác biệt giữa việc sử dụng; vs +
Ankur Agarwal

Tôi không nghĩ -1 là công bằng, tôi đã giải thích về người đàn ông của mình. Tôi không chỉ sao chép người đàn ông và rời đi. nhưng tôi đã chỉnh sửa phản hồi của mình để đưa vào một ví dụ tốt hơn.
trận đấu

10

findcó cú pháp đặc biệt. Bạn sử dụng {}như chúng là vì chúng có ý nghĩa để tìm làm tên đường dẫn của tệp tìm thấy và (hầu hết) shell không diễn giải chúng theo cách khác. Bạn cần dấu gạch chéo ngược \;bởi vì dấu chấm phẩy có ý nghĩa với vỏ, nó ăn nó trước khi findcó thể có được nó. Vì vậy, những gì findmuốn thấy SAU vỏ được thực hiện, trong danh sách đối số được truyền cho chương trình C, là

"-exec", "rm", "{}", ";"

nhưng bạn cần \;trên dòng lệnh để có một dấu chấm phẩy thông qua trình bao tới các đối số.

Bạn có thể nhận được ngay với \{\}vì việc giải thích vỏ trích dẫn của \{\}chỉ là {}. Tương tự, bạn có thể sử dụng '{}'.

Những gì bạn không thể làm là sử dụng

 -exec 'rm {} ;'

bởi vì shell giải thích rằng đó là một đối số,

"-exec", "rm {};"

rm {} ;không phải là tên của một lệnh. (Ít nhất là trừ khi ai đó thực sự vặn vẹo xung quanh.)

Cập nhật

sự khác biệt là giữa

$ ls file1
$ ls file2

$ ls file1 file2

Đây +là catenating tên vào một dòng lệnh.


1
Tôi hiểu những gì bạn đang nói. Tôi đang hỏi sự khác biệt giữa việc sử dụng; vs +
Ankur Agarwal

1
xin lỗi, nhưng bạn đã đọc câu hỏi của tôi hoặc bình luận của tôi một cách cẩn thận? Có thể tôi cần phải viết lại nó. Tại sao có một o / p khác nhau khi tôi sử dụng dấu chấm phẩy với exec trong find so với khi tôi sử dụng plus với exec in find?
Ankur Agarwal

2
Đây là một lời giải thích tuyệt vời cho TẠI SAO lệnh như thế này, rằng câu trả lời được chấp nhận không bao gồm. Cảm ơn!
Sherwin Yu

1

Sự khác biệt giữa ;(dấu chấm phẩy) hoặc +(dấu cộng) là cách các đối số được truyền vào find -exec/ -execdirtham số. Ví dụ:

  • bằng cách sử dụng ;sẽ thực thi nhiều lệnh (riêng cho từng đối số),

    Thí dụ:

    $ find /etc/rc* -exec echo Arg: {} ';'
    Arg: /etc/rc.common
    Arg: /etc/rc.common~previous
    Arg: /etc/rc.local
    Arg: /etc/rc.netboot
    

    Tất cả các đối số sau đây findđược coi là đối số cho lệnh.

    Chuỗi {}được thay thế bằng tên tệp hiện tại đang được xử lý.

  • bằng cách sử dụng +sẽ thực thi các lệnh ít nhất có thể (vì các đối số được kết hợp với nhau). Nó rất giống với cách xargshoạt động của lệnh, vì vậy nó sẽ sử dụng càng nhiều đối số trên mỗi lệnh càng tốt để tránh vượt quá giới hạn tối đa của đối số trên mỗi dòng.

    Thí dụ:

    $ find /etc/rc* -exec echo Arg: {} '+'
    Arg: /etc/rc.common /etc/rc.common~previous /etc/rc.local /etc/rc.netboot
    

    Dòng lệnh được xây dựng bằng cách nối thêm từng tên tệp được chọn ở cuối.

    Chỉ một trường hợp {}được cho phép trong lệnh.

Xem thêm:


-5

chúng tôi đã cố gắng tìm tập tin cho việc dọn phòng.

tìm thấy . -exec echo {} \; Lệnh chạy qua đêm cuối cùng không có kết quả.

tìm thấy . -exec echo {} \ + có kết quả và chỉ mất vài giờ.

Hi vọng điêu nay co ich.


2
Câu trả lời này không giải thích hai cách đó hoạt động như thế nào và kết quả do chúng tạo ra khác nhau như thế nào.
misko321
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.