Sự khác biệt của -a và -e trong các biểu thức điều kiện của bash là gì?


12

Từ man bash:

CONDITIONAL EXPRESSIONS
[...]
       -a file
              True if file exists.
[...]
       -e file
              True if file exists.
  1. Vì vậy, sự khác biệt giữa [ -a $FILE ][ -e $FILE ], nếu có?
  2. Nếu không có sự khác biệt thực sự, tại sao hai lá cờ cho cùng một mục đích tồn tại?

Chỉ các nhà phát triển mới biết # 2 --- trừ khi họ chia sẻ lý do của họ với cộng đồng.
Belmin Fernandez

Câu trả lời:


13

Trong bash, với bối cảnh của hai testlệnh đối số , -a file-e filegiống nhau. Nhưng họ có một số khác biệt, bởi vì -acũng là một toán tử nhị phân.

-eunary được định nghĩa bởi POSIX, nhưng -aunary thì không. POSIX chỉ định nghĩa -anhị phân (Xem POSIX thử nghiệm ).

POSIX định nghĩa ba testhành vi đối số :

3 đối số:

  • Nếu $ 2 là số chính nhị phân, hãy thực hiện kiểm tra nhị phân $ 1 và $ 3.

  • Nếu $ 1 là '!', Hãy phủ nhận bài kiểm tra hai đối số là $ 2 và $ 3.

  • Nếu $ 1 là '(' và $ 3 là ')', hãy thực hiện kiểm tra đơn phương là $ 2. Trên các hệ thống không hỗ trợ tùy chọn XSI, kết quả không được chỉ định nếu $ 1 là '(' và $ 3 là ')'.

  • Nếu không, tạo ra kết quả không xác định.

Vì vậy, -acũng dẫn đến kết quả kỳ lạ:

$ [ ! -a . ] && echo true
true

-ađược coi là toán tử nhị phân trong bối cảnh của ba đối số. Xem Bash FAQ câu hỏi E1 . POSIX cũng đề cập đến việc -alấy từ KornShell nhưng sau đó đã được thay đổi thành -evì nó gây nhầm lẫn giữa -anhị phân và -ađơn nguyên.

Chính -e, sở hữu chức năng tương tự như được cung cấp bởi trình bao C, đã được thêm vào vì nó cung cấp cách duy nhất cho tập lệnh shell để tìm hiểu xem một tệp có tồn tại mà không cố mở tệp không. Vì việc triển khai được phép thêm các loại tệp bổ sung, tập lệnh di động không thể sử dụng:

kiểm tra -b foo -o -c foo -o -d foo -o -f foo -o -p foo

để tìm hiểu xem foo là một tập tin hiện có. Trên các hệ thống BSD lịch sử, sự tồn tại của một tệp có thể được xác định bởi:

kiểm tra -f foo -o -d foo

nhưng không có cách nào dễ dàng để xác định rằng một tệp hiện có là một tệp thông thường. Một đề xuất ban đầu đã sử dụng KornShell -a chính (có cùng ý nghĩa), nhưng điều này đã được đổi thành -e vì có những lo ngại về khả năng cao con người nhầm lẫn giữa -a chính với toán tử nhị phân -a.

-anhị phân cũng được đánh dấu là lỗi thời, bởi vì nó dẫn đến một số biểu thức mơ hồ, có lớn hơn 4 đối số. Với biểu thức> 4 đối số này, POSIX xác định kết quả là không xác định.


Thật tuyệt khi biết! Bây giờ thì rõ hơn một chút :)!
polym

9

.1. Vậy đâu là sự khác biệt giữa [-a $ FILE] và [-e $ FILE], nếu có?

Không có sự khác biệt nào cả.

Xếp hàng 505-507trong test.cphiên bản bash 4.2.45(1)-release:

case 'a':           /* file exists in the file system? */
case 'e':
  return (sh_stat (arg, &stat_buf) == 0);

Điều đó chỉ ra rằng không có sự khác biệt thực sự giữa cả hai cờ.

.2. Nếu không có sự khác biệt thực sự, tại sao hai lá cờ cho cùng một mục đích tồn tại?

Xem câu trả lời của gnouc .


3
Mặt khác, cho rằng -acũng một nhà điều hành boolean (và) trong bash, có vẻ như lỗi dễ bị thêm ý nghĩa bổ sung này có nghĩa là hoàn toàn không cần thiết; Tôi đoán nó liên quan nhiều hơn đến khả năng tương thích với một số triển khai và / hoặc khả năng tương thích khác với các phiên bản trước đó không có -e.
celtschk

@celtschk - không phải là bugprone, nhưng trình phân tích cú pháp của shell có thể. POSIX chỉ định -a-obooleans cho [ test ]. Nhưng một số shell (như bash) hút vào việc phân biệt một đối số từ một toán tử và [ test ]kết quả là không đáng tin cậy. Kể từ đó, POSIX đã yêu cầu mọi trình bao tuân thủ xử lý ít nhất 4 đối số trong [ test ]ngoặc.
mikeerv

5

Câu trả lời tốt nhất tôi đã tìm thấy là câu hỏi này, từ câu hỏi StackOverflow:

-akhông được dùng nữa, do đó không được liệt kê trong trang hướng dẫn /usr/bin/testnữa, nhưng vẫn ở trong trang dành cho bash. Sử dụng -e. Đối với một '[', nội dung bash hoạt động giống như testnội dung bash, hoạt động giống như /usr/bin/[/usr/bin/test (cái này là một liên kết tượng trưng cho cái khác). Lưu ý ảnh hưởng của việc -aphụ thuộc vào vị trí của nó: Nếu nó bắt đầu, nó có nghĩa file exists. Nếu nó ở giữa hai biểu thức, nó có nghĩa là hợp lý and.

[ ! -a /path ] && echo existskhông hoạt động, vì hướng dẫn bash chỉ ra rằng nó -ađược coi là toán tử nhị phân ở đó, và do đó, phần trên không được phân tích cú pháp như một negate -a ..mà là if '!' and '/path' is true(không trống). Do đó, tập lệnh của bạn luôn xuất ra "-a"(thực sự kiểm tra các tệp) và "! -a"thực sự là tệp nhị phân andở đây.

[[, -akhông được sử dụng dưới dạng nhị phân andnữa ( &&được sử dụng ở đó), vì vậy mục đích duy nhất của nó là kiểm tra tệp ở đó (mặc dù không được dùng nữa). Vì vậy, phủ định thực sự làm những gì bạn mong đợi.

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.