GNU tìm và che dấu {} cho một số shell - cái nào?


34

Trang man cho GNU tìm trạng thái:

-exec command ;
    [...] The  string `{}'  is  replaced  by the current 
    file name being processed everywhere it occurs in the 
    arguments to the command, not just in arguments where 
    it is alone, as in some  versions  of  find.
    Both  of  these  constructions might need to be escaped 
    (with a `\') or quoted to protect them from expansion 
    by the shell. 

Đó là từ người đàn ông đến find(GNU findutils) 4.4.2.

Bây giờ tôi đã thử nghiệm điều này với bash và dash, và cả hai đều không cần phải {}đeo mặt nạ. Đây là một bài kiểm tra đơn giản:

find /etc -name "hosts" -exec md5sum {} \; 

Có một cái vỏ, mà tôi thực sự cần phải che mặt niềng răng? Lưu ý rằng nó không phụ thuộc vào việc tệp tìm thấy có chứa một khoảng trống (được gọi từ bash) hay không:

find ~ -maxdepth 1 -type d -name "U*" -exec ls -d {} \; 
/home/stefan/Ubuntu One

Điều này thay đổi nếu tệp tìm thấy được chuyển đến một khung con:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d {}' \; 
ls: cannot access /home/stefan/Ubuntu: No such file or directory
ls: cannot access One: No such file or directory

có thể được giải quyết bằng cách:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "$0"' {} \;

trái ngược với:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "{}"' \; 
/home/stefan/Ubuntu One

Nhưng đó không phải là những gì trang người đàn ông đang nói về, phải không? Vì vậy, vỏ nào xử lý {}theo một cách khác nhau?


@Volker Siegel: Chỉnh sửa của bạn có thể đã xảy ra với mục đích tốt, nhưng tôi đã kiểm tra hướng dẫn tìm kiếm hiện tại của tôi và sửa chữa của bạn là sai, Bạn cũng bỏ lỡ cơ hội để tóm tắt các chỉnh sửa của mình, đó là một thói quen xấu, vì vậy tôi khôi phục các thay đổi của bạn. Xin lỗi, đồng bào.
người dùng không xác định

Oh, cảm ơn bạn đã quay trở lại nếu nó phá vỡ một cái gì đó. Tôi đã nhớ rằng trình biên dịch văn bản tạo định dạng trang man được sử dụng để tạo ra các "trích dẫn chính tả" này như là một tạo tác của định nghĩa kết xuất. Nó cũng có thể kết xuất với TeX để định dạng bản in hoàn hảo. Tôi nhận thấy các trích dẫn bởi vì họ nhầm lẫn cú pháp tô sáng. Tôi giả sử rằng trích dẫn đầu tiên bất thường là sai khi được sử dụng trong mã, và vẫn cho rằng. Lưu ý rằng hai thay đổi là trong văn bản mô tả, không phải mã. Vì vậy, nếu chúng ta xem chúng là kiểu chữ - kết xuất thẩm mỹ - thì chúng đúng.
Volker Siegel

Hình như trong kết xuất đầu ra thông tin, cùng một trích dẫn được sử dụng ở cả hai bên. Không có nghi ngờ gì về sự thay đổi của tôi làm cho nó khác với bản gốc, bạn đã đúng. Nhưng nó có gây ra vấn đề gì không? (Tôi coi trích dẫn đầu tiên là một lỗi trong định nghĩa kết xuất của người đàn ông, đó là trường hợp duy nhất về kiểu chữ theo như tôi biết.)
Volker Siegel

Tôi vừa kiểm tra: `{} 'không hoạt động trên dòng lệnh. Điều đó đúng về mặt kỹ thuật, nhưng tôi không thích rằng một người dùng không ngờ tới sẽ gặp một lỗi lạ khi anh ta cố gắng sao chép và dán nó.
Volker Siegel

@VolkerSiegel: Đây là văn bản văn xuôi, không phải mã, vậy người dùng sao chép-dán ở đây là gì? Và đó là một trích dẫn của trang man từ năm 2011. Tôi không thấy bất kỳ giá trị nào sửa lỗi đoạn văn sau đó chỉ ra, tại sao tôi lại chỉnh sửa trang man. Chủ đề đủ phức tạp. Nếu đây là câu hỏi của bạn, tôi sẽ không cố gắng thuyết phục bạn, trích dẫn chính xác trang người đàn ông nhưng đối với câu hỏi của tôi, tôi không có tâm trạng làm thỏa hiệp. Trích dẫn là trích dẫn.
người dùng không xác định

Câu trả lời:


26

Tóm tắt : Nếu đã từng có một cái vỏ được mở rộng {}, thì bây giờ nó thực sự là thứ cũ.

Trong vỏ Bourne và trong vỏ POSIX-compliant, niềng răng ( {}) là nhân vật bình thường (không giống như ()đó là delimiters từ như ;&, và []được globbing ký tự). Các chuỗi sau đây đều được cho là được in theo nghĩa đen:

$ echo { } {} {foo,bar} {1..3}
{ } {} {foo,bar} {1..3}

Một từ bao gồm một dấu ngoặc đơn là một từ dành riêng , nó chỉ đặc biệt nếu đó là từ đầu tiên của lệnh.

Ksh thực hiện mở rộng dấu ngoặc như một phần mở rộng không tương thích với vỏ Bourne. Điều này có thể được tắt với set +B. Bash mô phỏng ksh về mặt này. Zsh thực hiện mở rộng cú đúp là tốt; ở đó nó có thể được tắt với set +Ihoặc setopt ignore_braceshoặc emulate sh. Không ai trong số những vỏ mở rộng {}trong mọi trường hợp, ngay cả khi đó là một chuỗi con của một từ (ví dụ foo{}bar), do việc sử dụng phổ biến trong các đối số findxargs.

Unix v2 duy nhất lưu ý rằng

Trong một số hệ thống lịch sử, các dấu ngoặc nhọn được coi là toán tử điều khiển. Để hỗ trợ các hoạt động tiêu chuẩn hóa trong tương lai, các ứng dụng di động nên tránh sử dụng dấu ngoặc nhọn không được trích dẫn để thể hiện chính các ký tự. Có thể phiên bản tương lai của tiêu chuẩn ISO / IEC 9945-2: 1993 có thể yêu cầu điều đó {}được coi là các toán tử điều khiển, mặc dù mã thông báo {}có thể sẽ được miễn trừ trong trường hợp đặc biệt vì find {}cấu trúc thường được sử dụng .

Lưu ý này đã bị loại bỏ trong các phiên bản tiếp theo của tiêu chuẩn; các ví dụ cho việcfind sử dụng không được trích dẫn {}, cũng như các ví dụ choxargs . Có thể đã có những chiếc vỏ Bourne lịch sử {}phải được trích dẫn, nhưng bây giờ chúng sẽ là những hệ thống di sản thực sự cũ.

Các triển khai csh tôi có trong tay (OpenBSD 4.7, BSD csh trên Debian , tcsh) đều mở rộng {foo}sang foonhưng để {}yên.


1
@geekizard: Chỉ một tập hợp nhỏ của markdown hoạt động trong các bình luận . Tôi không biết bạn đang cố nói gì. Nếu đây là về việc mở rộng cú đúp của ksh et al, hãy đọc đoạn văn của tôi bắt đầu bằng cách Ksh thực hiện mở rộng cú đúp như một phần mở rộng không tương thích.
Gilles 'SO- ngừng trở thành ác quỷ'

2
Đó là bash(xem $BASH_VERSION). Mở rộng cú đúp là rất nhiều sống và tốt.
geekizard

2
Đó điểm. Các {}cú pháp có nguồn gốc từ csh, nhưng {}mở rộng đến các chuỗi rỗng. Các vỏ mới hơn nhận ra rằng đó là vô nghĩa, nhưng vẫn còn một số cũ csh.
geekizard

1
@geekizard: Bạn có thể nói phiên bản csh cụ thể nào trên nền tảng cụ thể nào không? Tôi muốn tự kiểm tra nó (nếu có thể trên linux) hoặc yên tâm, rằng người đó đã tự kiểm tra nó.
người dùng không xác định

1
@geekizard, {}foosẽ mở rộng sang foo, nhưng {}sẽ mở rộng sang {}(trừ khi trong backticks, nhưng trích dẫn sẽ không giúp ích) và đã được ghi lại như vậy. Tôi đã xác minh nó cho csh của 2BSD (bản phát hành đầu tiên), 2,79BSD, 2,8BSD và 2,11BSD.
Stéphane Chazelas

12

Các {}cần phải được trích dẫn trong các phiên bản của fishvỏ trước 3.0.0.

$ fish -c 'echo find -exec {} \;'
find -exec  ;

Và trong vỏ RC (cũng akangadựa trên rc, nhưng không es):

$ rc -c "echo find -exec {} ';'"
line 1: syntax error near '{'

Đó có lẽ không phải là vỏ mà các tác giả của GNU tìm thấy tài liệu đã ghi nhớ khi họ viết văn bản đó kể từ fishlần đầu tiên được phát hành vào năm 2005 (trong khi văn bản đó hoặc tương tự đã có ở đó vào năm 1994) và rcban đầu không phải là vỏ Unix.

Có một số tin đồn về một số phiên bản csh(vỏ đã giới thiệu mở rộng nẹp) yêu cầu nó. Nhưng thật khó để cung cấp tín dụng cho những người kể từ lần phát hành đầu tiên cshtrong 2BSD. Ở đây như đã được thử nghiệm trong trình giả lập PDP11:

# echo find -exec {} \;
find -exec {} ;

trang người đàn ông từ 2BSD cshnêu rõ :

Như một trường hợp đặc biệt `{',`}' và `{} 'được truyền không bị xáo trộn.

Vì vậy, tôi sẽ thấy rất kỳ lạ nếu một phiên bản tiếp theo của csh hoặc tcsh sau đó đã phá vỡ điều đó.

Nó có thể đã được khắc phục một số lỗi trong một số phiên bản. Vẫn với csh 2BSD đó (tương tự trong 2,79BSD, 2,8BSD, 2,11BSD):

# csh -x
# echo foo {} bar
echo foo {} bar
foo {} bar
# echo `echo foo {} bar`
echo `echo foo {} bar`
echo foo {} bar
foo  bar

Trích dẫn không giúp đỡ mặc dù:

# echo `echo foo '{}' bar`
echo `echo foo '{}' bar`
echo foo {} bar
foo  bar

Bạn có thể trích dẫn toàn bộ thay thế lệnh:

# echo "`echo foo {} bar`"
echo `echo foo {} bar`
echo foo {} bar
foo {} bar

Nhưng đó là truyền một lý lẽ cho tiếng vang bên ngoài đó.

Trong cshhoặc tcsh, bạn cần trích dẫn {}khi không tự mình như trong:

find . -name '*.txt' -type f -exec cp {} '{}.back' \;

(mặc dù loại findsử dụng đó không khả dụng vì một số finds chỉ mở rộng {}khi tự sử dụng).


1

Trong một từ , csh. bashvà các shell hiện đại khác nhận ra rằng người dùng có thể không yêu cầu mở rộng niềng răng null. (Hiện đại cshthực sự tcshvà cũng có thể xử lý hoàn toàn {}ngay bây giờ.)


Rất vui được nghe, nhưng tôi đang hỏi ngược lại, một cái vỏ không xử lý nó hoàn toàn.
người dùng không xác định

Bạn đang giả định rằng ai đó sẽ đi vào và rip ra tham khảo các trang thông tin để thêm trích dẫn chỉ vì hệ thống Linux đều có phiên bản mới hơn csh. Không phải ai cũng chạy các tiện ích GNU trên Linux; trong thực tế, việc cài đặt chúng trên các hệ thống Unix thương mại cũ có lệnh bị bó rất hạn chế. (Việc thay thế cshtrên các hệ thống đó ít có khả năng hơn, bởi vì các tập lệnh hệ thống có thể dựa vào các đặc điểm riêng của bản gốc cshvà ngay cả khi người dùng được cấu hình để sử dụng phiên bản mới hơn csh, rootgần như chắc chắn sẽ vẫn phải là phiên bản đi kèm.)
geekizard

2
Không. Tôi đang tranh luận với một anh chàng nói rằng, trong wiki của chúng tôi, chúng tôi nên đưa ra lời khuyên để sử dụng "{}" mọi lúc, bởi vì trang nam nói như vậy. Và bây giờ tôi muốn biết nếu có một cái vỏ mà tôi không sử dụng, như ksh, zsh, tcsh, csh hoặc XYZsh mà tôi không biết, mà tuyên bố này là đúng, hoặc liệu tôi có thể giả định một cách trung thực không không có Nếu có shell cho các Unix khác nhau cần "{}", đó sẽ là một lời giải thích tốt tại sao câu vẫn ở trong trang man, nhưng không phù hợp như lời khuyên cho người mới bắt đầu sử dụng linux.
người dùng không xác định

Bây giờ tôi đang tự hỏi liệu pdkshđiều đó có đúng không ... mặc dù câu trả lời đúng cho điều đó có lẽ là "thực sự kshlà FOSS những ngày này".
geekizard

4
Pdksh, như mksh, ksh93, bash và zsh, chỉ mở rộng dấu ngoặc khi có dấu phẩy ở giữa (hoặc ..cho ksh93, bash và zsh). Chỉ nở (t) csh {foo}đến foo, và thậm chí nó để lại {}một mình (ít nhất là trên gần đây của BSD).
Gilles 'SO- đừng trở nên xấu xa'
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.