2010-03-11 5 views
30

Tôi đang sử dụng tìm cho một công việc và tôi nhận thấy rằng khi tôi làm điều gì đó như thế này:Tại sao sử dụng tên dirname trong lệnh tìm cho dấu chấm cho mỗi trận đấu?

find `pwd` -name "file.ext" -exec echo $(dirname {}) \; 

nó sẽ cho bạn chấm duy nhất cho mỗi trận đấu. Khi bạn thay thế dirname bằng basename trong lệnh đó, bạn sẽ nhận được tên đầy đủ. Tôi có vặn cái gì đó ở đây hay là hành vi mong đợi này? Tôi được sử dụng để basename cung cấp cho bạn tên của tệp (trong trường hợp này là file.ext) và dirname cung cấp cho bạn phần còn lại của đường dẫn.

Trả lời

24

Hãy xem xét kịch bản sau đây:

#!/bin/sh 
set -x 
find `pwd` -name "file.ext" -exec echo $(dirname {}) \; 

set -x cho thấy cách thức hoạt động mở rộng và những gì các lệnh cuối cùng là. Khi chạy, nó cung cấp kết quả sau:

++ pwd 
++ dirname '{}' 
+ find /home/kibab -name file.ext -exec echo . ';' 

Vì vậy, điều đầu tiên được mở rộng là pwd. Thứ hai là $(dirname {}). Kết quả của hai lệnh này sau đó được thả vào lệnh find. Vì vậy, bạn đang nói tìm thấy -exec echo ., vì vậy bạn sẽ thấy kết quả mong đợi.

Khi bạn thay basename cho dirname, việc mở rộng vẫn có nơi, nhưng kết quả của việc mở rộng khác nhau:

  1. pwd được mở rộng với các đường dẫn hiện hành. Trong ví dụ trên của tôi, kết quả là /home/kibab
  2. basename {} được thực thi. Kết quả của lệnh này là {}.
  3. Lệnh tìm được thực hiện với các thay thế ở trên tại chỗ. Lệnh thức thực hiện như sau:

    find /home/kibab -name '*.png' -exec echo '{}' ';'

Sau khi kiểm tra lệnh trên, bạn sẽ nhận thấy rằng các lệnh bây giờ chỉ đơn giản là tiếng vang của bất cứ tập tin đã được tìm thấy.

Có lẽ bạn muốn một cái gì đó như thế này?

find `pwd` -name "file.ext" -printf "%f\n" 
+0

@ Martin - Điểm tốt, đã thêm giải thích. –

+0

Điều này đã giúp một tấn. Tôi không biết về set-x, và bối cảnh duy nhất tôi đã sử dụng basename/dirname là khi tôi đã đặt nó vào một biến. – temp2290

+0

Bạn có thể muốn xem 'set -v' và một số tùy chọn khác của tập hợp. Chúc may mắn. –

4

Tôi không biết lý do tại sao bạn đang nhận được đó, nhưng cố gắng này:

find `pwd` -name file.ext |xargs -l1 dirname 
+0

Điều này thực sự đã giúp, mặc dù tôi đã phải thay thế chữ thường 'l' bằng chữ hoa. Tại sao điều này làm việc như mong đợi, nhưng '... | xargs dirname' không? –

0

Điều này là do find in đường dẫn tương đối so với con đường nó tìm kiếm từ. Nếu bạn đã thử tìm kiếm này từ /, bạn sẽ nhận được `` pwd \ cho mỗi đường dẫn.

4

$(dirname {}) được đánh giá bởi vỏ trước khi được chuyển đến find. Kết quả của đánh giá này là ., vì vậy, bạn chỉ cần yêu cầu find thực thi echo . cho mỗi tệp mà nó tìm thấy.

basename {} đánh giá để {}, vì vậy với $(basename {}) thay thế cho $(dirname {}), find sẽ thực hiện echo {} cho mỗi file. Điều này dẫn đến tên đầy đủ của mỗi tập tin được lặp lại.

Nếu bạn muốn đầu ra là kết quả của dirname cho mỗi tập tin tìm thấy, bạn có thể bỏ qua echo:

find `pwd` -name "file.ext" -exec dirname {} \; 
8

bạn không cần phải gọi dirname() cho mỗi tập tin được tìm thấy. với GNU tìm, bạn có thể sử dụng -printf và nhanh hơn của nó theo cách này

find /path -type f -iname "*.ext" -printf "%h\n" 
17

Vì vậy, vấn đề là $ (...) hoặc `...` bắt đầu một vỏ mới trước khi thực hiện việc thay đổi.

Xem xét sử dụng bash -c:

$ find . -name '*.PNG' -exec bash -c 'git mv {} $(dirname {})/$(basename {} .PNG)48.png' \; 

Đó đổi tên bất kỳ biểu tượng trên một repo git mẫu chuẩn hơn.

Tại đây {} được thay thế trước khi thực hiện bất kỳ điều gì, do đó sự cố đã biến mất.

Ví dụ, TMTOWTDI, nhưng tôi cố gắng giữ cho nó đơn giản để bạn có thể bắt đầu bất cứ điều gì bạn thực sự cần phải làm.

2

Nó hiển thị cho bạn các dấu chấm, bởi vì quá trình thay thế được đánh giá trước khi lệnh được thực thi. Vì vậy, bạn đã vượt qua lệnh của bạn vào trường hợp vỏ riêng biệt.

Đối với cách giải quyết, sử dụng cú pháp sau:

find $PWD -name "file.ext" -exec sh -c 'echo $(dirname {})' ';' 

Tuy nhiên cách dễ nhất để in hoặc thực hiện một cái gì đó trong mỗi thư mục là bởi -execdir, ví dụ:

find . -name "file.ext" -execdir pwd ';' 
+0

Đây là câu trả lời duy nhất phù hợp với tôi! – Leonmax