FreeBSD lỗi tập thể
Tôi muốn đưa shebang #!/bin/sh -eufo pipefailvào kịch bản của mình. Nhưng có một số điều kỳ lạ:
- Tập lệnh sẽ không thành công với shebang đó trong FreeBSD nhưng không phải khi chạy trên MacOS
- trên FreeBSd, shebang tương tự hoạt động khi được thực thi trực tiếp từ dòng lệnh (cũng
/bin/sh).
>>> sh -eufo pipefail -c 'echo hi' # this works
hi
>>> cat <<EOF > script
#!/bin/sh -eufo pipefail
echo hi
EOF
>>> chmod +x ./script
>>> ./script # this doesn't work on FreeBSD but works on MacOS
Illegal option -o ./script
>>> cat ./script
#!/bin/sh -eufo pipefail
echo hi
>>> uname -a
FreeBS 11.3-RELEASE-p7
Trả lời
MacOS vẫn giữ nguyên trạng FreeBSD cũ từ trước năm 2005. Vào năm 2005, đã có một sự thay đổi lớn trong cách xử lý hạt nhân FreeBSD #!khi bắt đầu tệp thực thi được chuyển đến execve(), để làm cho nó phù hợp hơn với một số hạt nhân hệ điều hành khác, bao gồm Linux và hạt nhân NetBSD.
Chú thích trong mã nguồn hạt nhân NetBSD cố gắng vẽ điều này như một cái chung:
* thu thập đối số shell. mọi thứ sau tên vỏ * được chuyển dưới dạng MỘT đối số; đó là chính xác (lịch sử) * hành vi.-kern/exec-script.c. NetBSD. dòng 189 et seq ..
Nó thực sự không phải. Sven Mascheck đã thực hiện một số thử nghiệm khoảng một thập kỷ trước và có bốn hành vi cơ bản, Hệ thống AT&T Unix 5, một hành vi có nhiều tuyên bố là hành vi "lịch sử chính xác" như 4.2BSD có:
- Bỏ qua các ký tự (trước 4.2BSD và AT&T Unix System 5).
- Chuyển toàn bộ chuỗi trong một đối số (4.2BSD, NetBSD, Linux và FreeBSD từ 2005 trở đi).
- Chia chuỗi theo khoảng trắng và chuyển nó dưới dạng nhiều đối số (FreeBSD trước 2005 và MacOS).
- Chia chuỗi thành khoảng trắng và chỉ chuyển đối số đầu tiên (AT&T Unix System 5 và Solaris)
Tôi chỉ bao gồm các hệ điều hành có liên quan đến câu trả lời này trong ngoặc đơn. M. Mascheck đã kiểm tra nhiều hơn, cũng như Ahmon Dancy trong cuộc thảo luận về Báo cáo sự cố FreeBSD 16393. Xem phần đọc thêm để biết danh sách đầy đủ.
Điều khiến mọi thứ trở nên nổi bật trong FreeBSD vào năm 2005 là, trớ trêu thay, FreeBSD không hoàn toàn đơn giản như vậy. Nó đã có một thay đổi được giới thiệu nhằm mục đích làm cho những điều được viết trong các cuốn sách nổi tiếng về Perl thực sự hoạt động: các lập luận được bỏ qua sau một ký tự bình luận. Những cuốn sách đã đề xuất những điều như:
#! / bin / sh - # - * - perl - * -- Larry Wall, Tom Christiansen, Jon Orwant (2000). Lập trình Perl: Phiên bản thứ 3 . O'Reilly Media. ISBN 9780596000271. tr. 488.
PR 16393 vào năm 2000 là một cách làm cho hạt nhân xử lý các tập lệnh Perl thực thi được, được viết theo cách mà Larry Wall đã nói sẽ hoạt động. Tuy nhiên, nó đã phá vỡ những thứ khác và không hoàn toàn hoạt động.
Có một số qua lại về điều này. Cuối cùng, vào năm 2005, cơ chế để thực hiện ý tưởng của Larry Wall và cộng sự đã được chuyển ra khỏi nhân, được tạo ra để hoạt động tương thích với Linux, NetBSD và 4.2BSD (chứ không phải Solaris và AT&T Unix System 5) và được trách nhiệm của sh.
Do đó, hành vi kể từ năm 2005 là shell nhận được ba đối số, đối số thứ hai là toàn bộ phần đuôi của #!dòng và việc gọi trực tiếp tập lệnh của bạn execve()cũng giống như gọi:
sh '-eufo pipefail' ./script
Sẽ khá rõ ràng tại sao trình bao Almquist (là những gì shcó trên FreeBSD) lại nghĩ rằng đó ./scriptlà đối số tùy chọn cho -otùy chọn và rằng nó đang coi pipefailphần này là các tùy chọn đơn chữ cái khác được thu thập phía sau -(mà nó không có xung quanh để xử lý chưa).
Một giải pháp thay thế hiển nhiên khác là có set -o pipefaillệnh đầu tiên trong tập lệnh, như được chỉ ra tạihttps://unix.stackexchange.com/a/533418/5132cho vỏ Bourne Again . Tuy nhiên, điều này chỉ được thêm vào trình bao FreeBSD Almquist vào năm 2019 và do đó chỉ có sẵn trong các phiên bản FreeBSD rất gần đây. (Trình bao Debian Almquist vẫn chưa được thêm vào, kể từ năm 2020)
đọc thêm
- Trỏ đến một số lịch sử cũ hơn: https://unix.stackexchange.com/a/489688/5132
- Sven Mascheck. " Kết quả thử nghiệm từ các hệ thống khác nhau ". Sự
#!kỳ diệu, chi tiết về cơ chế shebang / hash-bang trên các phiên bản Unix khác nhau . www.in-ulm.de/~mascheck . - G clear A Drosihn (2005-02-23). Lỗi trong #! xử lý - Thêm một lần nữa. danh sách gửi thư freebsd-Arch.
- ryand (2000-01-27).
/bin/shkhông tước bình luận trên dòng shebang . Báo cáo sự cố FreeBSD 16393. - G clear A Drosihn (2005). Cập nhật ghi chú cho ngày 28 tháng 5 năm 2005: Thay đổi trong việc xử lý các tùy chọn shell-script . people.freebsd.org/~gad.
sh. Sổ tay hướng dẫn sử dụng lệnh chung BSD . Ngày 24 tháng 2 năm 2019. freebsd.org.- Wolfram Schneider (tháng 12 năm 2017). Nhận trạng thái thoát của quy trình được chuyển đến một quy trình khác:
set -o pipefailbị thiếu đối với/bin/sh. Báo cáo sự cố FreeBSD 224270. - Ibrahim Ghazal (2020-06-30). Tình trạng của
set -o pipefail. Danh sách gửi thư shell Debian Almquist.
Mặc dù #!cách sử dụng của bạn là không di động vì nó sử dụng nhiều hơn những điều đơn giản:
#!/bin/sh
hoặc đối số duy nhất thường được hỗ trợ như trong:
#!/bin/sh -oneflag
Vấn đề thực sự là bạn đang sử dụng tùy chọn không di động -o pipefail.
Đây là một tùy chọn từ ksh93và bashkhông được hỗ trợ bởi các trình bao khác.
Lý lịch:
Trên hệ điều hành MacOS,
/bin/shlàbashđã được biên soạn một cách cụ thể (ví dụ như để làm cho trình tự thoát trongechoviệc theo mặc định) để làm cho nó POSIX tuân thủ. Vì bash hỗ trợpipefail(xem ở trên), điều này hoạt động trên MacOS.Trên FreeBSD,
/bin/shlàashkhông hỗ trợpipefail.
Bạn có hai cách khả thi:
Không được dùng
set -o pipefailChờ hai năm và thử lại. Điều này rất có thể sẽ hoạt động, vì chúng tôi đã quyết định thêm tùy chọn này vào tiêu chuẩn POSIX tiếp theo (Vấn đề-8) 10 tháng trước, hãy xemhttps://www.austingroupbugs.net/view.php?id=789và vì tiêu chuẩn POSIX tiếp theo sẽ được xuất bản trong khoảng. một năm, có một cơ hội lớn mà FreeBSD sẽ hỗ trợ thêm cho
set -o pipefailđếnashsớm.