Làm thế nào để 'find -exec' vượt qua tên tệp có dấu cách?


14

Nếu tôi có một thư mục chứa một số tệp có tên có khoảng trắng, vd

$ ls -1 dir1
file 1
file 2
file 3

Tôi có thể sao chép thành công tất cả chúng vào một thư mục khác như thế này:

$ find dir1 -mindepth 1 -exec cp -t dir2 {} +

Tuy nhiên, đầu ra của find dir1 -mindepth 1không gian không thoát:

$ find dir1 mindepth 1
dir1/file 1
dir1/file 3
dir1/file 3

Nếu tôi sử dụng print0thay vì print, đầu ra vẫn chứa các khoảng trắng chưa thoát:

$ find dir1 mindepth 1 -print0
dir1/file 1dir1/file 2dir1/file 3

Để sao chép các tệp này theo cách thủ công bằng cách sử dụng cp, tôi sẽ cần phải thoát khoảng trắng; nhưng có vẻ như điều này là không cần thiết khi cpcác bản sao xuất phát find, bất kể tôi sử dụng +hay \;ở cuối lệnh.

Lý do cho điều này là gì?

Câu trả lời:


8

Các find lệnh thực hiện lệnh trực tiếp. Lệnh, bao gồm đối số tên tệp, sẽ không được xử lý bởi trình bao hoặc bất kỳ thứ gì khác có thể sửa đổi tên tệp. Nó rất an toàn.

Bạn đúng rằng không cần phải thoát tên tập tin được thể hiện {}trên finddòng lệnh.

findchuyển tên tệp thô từ đĩa trực tiếp vào danh sách đối số bên trong của -execlệnh, trong trường hợp của bạn là cplệnh.


1
Tóm lại, find..execcó thể tự xử lý tên tập tin kỳ lạ ..
heemayl

2
Nguyên tắc đầu tiên của câu lạc bộ linux là bạn không phân tích ls
Sergiy Kolodyazhnyy

5

Câu hỏi gồm hai phần:

  • Làm thế nào để find quản lý để gọi các chương trình bằng cách sử dụng -execmà không gặp vấn đề với các khoảng trắng được nhúng trong tên tệp và
  • những gì tốt là -print0lựa chọn?

Đối với người đầu tiên, findđang thực hiện một cuộc gọi hệ thống, thực sự là một trong một nhóm các cuộc gọi liên quan được gọi là "exec" . Nó chuyển tên tệp dưới dạng đối số trực tiếp cho cuộc gọi này, sau đó được truyền trực tiếp (sau khi tạo quy trình mới) mà không làm mất thông tin về tên tệp.

findTính năng POSIX +được giải thích như sau, theo lý do :

Một tính năng của findtiện ích SVR4 là dấu -execkết thúc + chính. Điều này cho phép tên tệp chứa các ký tự đặc biệt (đặc biệt là các tự dòng mới ) được nhóm lại với nhau mà không gặp sự cố xảy ra nếu tên tệp đó được chuyển sang xargs. Các triển khai khác đã thêm các cách khác để khắc phục vấn đề này, đáng chú ý là một -print0chính đã viết tên tệp bằng một bộ kết thúc byte rỗng. Điều này đã được xem xét ở đây, nhưng không được thông qua. Sử dụng một bộ kết thúc null có nghĩa là bất kỳ tiện ích nào sẽ xử lý -print0đầu ra của find phải thêm một tùy chọn mới để phân tích các bộ kết thúc null mà nó sẽ đọc.

Điều đó " đáng chú ý-print0chính" đề cập đến GNU findxargsgiải quyết vấn đề theo một cách khác. Nó cũng được hỗ trợ bởi FreeBSD findxargs. Nếu bạn đã thêm một -0tùy chọn (xem trang thủ công ) vào xargscuộc gọi, thì chương trình đó chấp nhận các dòng kết thúc bằng ký tự "null byte". Đổi lại, xargsgọi hàm exec -fifts để thực hiện công việc của nó . Sự khác biệt chính giữa tính năng -print0-0tính năng so với +tính năng là cái trước vượt qua tên tệp qua một ống, trong khi cái sau thì không. Các nhà phát triển tìm thấy việc sử dụng cho hầu hết các tính năng; Các đường ống cũng không ngoại lệ.

Quay lại ví dụ của OP, sử dụng một -ttùy chọn để cp: không tìm thấy trong POSIX cp . Thay vào đó, nó là một phần mở rộng (còn gọi là "tính năng không chuẩn") được cung cấp bởi GNU cp . Việc -0mở rộng xargssẽ không cải thiện ví dụ này, nhưng có những trường hợp khác có thể sử dụng nó một cách hiệu quả, hãy nhớ rằng có một giải pháp thay thế di động +, mà GNU findchấp nhận.


-1

( Đây phải là một nhận xét nhưng nó quá lớn. )

Đối với những người thích thử mọi thứ:

Tạo một kịch bản liệt kê các tham số vị trí được truyền vào, gọi nó list_positional_parameters.sh.

#!/bin/bash

# http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_09_07.html
# Try globbing patterns, e.g. "X[[:digit:]][[:digit:]]" to see what happens

if [ $# -lt 1 ]; then
   echo "Usage: $0 and then at least one parameter"
   exit 1
fi

counter=1

while (($#)); do
   echo "$counter = '$1'"
   # pop positional argument 1 off the stack of positional arguments
   shift
   (( counter++ ))
done

Chạy findvới nó trên một số thư mục $ dir:

find "$dir" -exec ./list_positional_parameters.sh '{}' ';' | less

Như mong đợi, chỉ có một tham số duy nhất trong tất cả các cuộc gọi, tên tệp, cho dù có khoảng trắng trong tên của nó hay không.


1
Bạn cũng có thể sử dụng printfnhư printf '"%s"\n' "$@"để in ra tất cả các đối số vị trí được trích dẫn, để kiểm tra trực quan.
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.