Viết các kịch bản shell sẽ chạy trên bất kỳ shell nào (sử dụng nhiều dòng shebang?)


19

Tôi mới bắt đầu tìm hiểu sâu hơn về kịch bản shell và tôi luôn ném tập lệnh của mình vào một tệp, đánh dấu nó chmod +xvà sau đó thực hiện /path/to/script.shvà để bất kỳ trình thông dịch nào là mặc định theo cách của nó, mà tôi giả sử là zsh bởi vì đó là những gì Tôi đã sử dụng cho vỏ của tôi. Rõ ràng có vẻ như đó chỉ là /bin/shmặc định, ngay cả khi tôi thực thi tập lệnh từ dấu nhắc zsh, bởi vì tôi đã bắt đầu đưa nội dung cụ thể zsh vào tập lệnh của mình và nó không thành công trừ khi tôi chạy zsh /path/to/script.sh.

Để đi đến vấn đề, đây là câu hỏi của tôi:

  1. Shell nào thực thi các tập lệnh khi không có dòng shebang ( #!/path/to/shell) ở đầu? Tôi giả sử /bin/shnhưng tôi không thể xác nhận.
  2. Điều gì được coi là "thực tiễn tốt nhất" về mặt viết kịch bản shell sẽ chạy trên bất kỳ nền tảng nào? (ok, đây là loại kết thúc mở)
  3. Có thể viết một tập lệnh cố gắng sử dụng zsh và quay lại bash nếu zsh không có sẵn? Tôi đã thử đặt hai dòng shebang, như bên dưới, nhưng nó chỉ bị lỗi bad interpreter: /bin/zsh: no such file or directorynếu tôi thử nó trên máy không có zsh.

    #!/bin/zsh

    #!/bin/bash

Câu trả lời:


26

Shell nào thực thi các tập lệnh khi không có dòng shebang (#! / Path / to / shell) ở đầu? Tôi giả sử / bin / sh nhưng tôi không thể xác nhận.

Hạt nhân từ chối thực hiện kịch bản và lợi nhuận như vậy ENOEXEC, vì vậy hành vi chính xác phụ thuộc vào chương trình bạn chạy một kịch bản như vậy từ .

  • bash 4.2.39 - sử dụng chính nó
  • busybox-ash 1.20.2 - sử dụng chính nó
  • dấu gạch ngang 0,5,7 - lượt chạy / thùng / sh
  • cá 1.23.1 - phàn nàn về ENOEXEC, sau đó đổ lỗi cho tệp sai
  • AT & T ksh 93u + 2012.08.01 - sử dụng chính nó
  • mksh R40f - chạy / bin / sh
  • pdksh 5.2,14 - chạy / bin / sh
  • sh-heirloom 050706 - sử dụng chính nó
  • tcsh 6.18.01 - chạy / bin / sh
  • zsh 5.0.0 - chạy / bin / sh
  • cmd.exe 5.1.2600 - nhìn bạn buồn cười.

Trong glibc , các chức năng execv()hoặc execve()chỉ trả về ENOEXEC. Nhưng execvp()ẩn mã lỗi này và tự động gọi / bin / sh. (Điều này được ghi lại trong exec (3p) .)

Điều gì được coi là "thực tiễn tốt nhất" về mặt viết kịch bản shell sẽ chạy trên bất kỳ nền tảng nào? (ok, đây là loại kết thúc mở)

Chỉ dính vào shvà chỉ các tính năng do POSIX xác định hoặc chỉ cần sử dụng bash đầy đủ (có sẵn rộng rãi) và đề cập đến nó trong các yêu cầu của bạn nếu phân phối nó.

(Bây giờ tôi nghĩ về nó, Perl - hoặc có lẽ là Python - thậm chí còn dễ mang theo hơn, chưa kể đến việc có một cú pháp tốt hơn.)

Luôn luôn thêm dòng shebang. Nếu sử dụng bash hoặc zsh, hãy sử dụng #!/usr/bin/env bashthay vì mã hóa đường dẫn của shell. (Tuy nhiên, vỏ POSIX được đảm bảo là có /bin/sh, vì vậy bỏ qua envtrong trường hợp đó.)

(Thật không may, thậm chí /bin/shkhông phải lúc nào cũng giống nhau. Chương trình autoconf GNU phải đối phó với nhiều quirks khác nhau .)

Có thể viết một tập lệnh cố gắng sử dụng zsh và quay lại bash nếu zsh không có sẵn? Tôi đã thử đặt hai dòng shebang, như bên dưới, nhưng nó chỉ gặp lỗi với trình thông dịch xấu: / bin / zsh: không có tệp hoặc thư mục nào như vậy nếu tôi thử nó trên máy không có zsh.

Chỉ có thể có một dòng shebang; mọi thứ sau ký tự dòng mới thậm chí không được đọc bởi kernel và được coi là một nhận xét bằng shell.

thể viết một tập lệnh chạy dưới dạng #!/bin/sh, kiểm tra xem shell nào có sẵn và chạy exec zsh "$0" "$@"hoặc exec bash "$0" "$@"tùy thuộc vào kết quả. Tuy nhiên, cú pháp được sử dụng bởi bash và zsh rất khác nhau ở những nơi khác nhau mà tôi không khuyên bạn nên làm điều này vì sự tỉnh táo của riêng bạn.


1
Làm thế nào bạn theo dõi những gì mỗi vỏ thực sự được gọi khi nhận được ENOEXEC?
swrobel

2
@SWrobel: Sử dụng strace -f -e fork,clone,execve. Một số đạn pháo tiếp tục thực hiện /bin/shsau khi thất bại; những người khác tự giải thích kịch bản.
grawity

1
@SWrobel: Một phương pháp khác là chạy một tập lệnh bao gồm readlink /proc/$$/exe.
grawity


1
Đối với cshtcsh, hành vi phụ thuộc vào việc tập lệnh bắt đầu bằng #(trong trường hợp đó chúng tự gọi thay vì sh để giải thích tập lệnh). Điều đó quay trở lại thời điểm khi csh ủng hộ các bình luận nhưng không phải là vỏ Bourne, vì vậy #một gợi ý rằng đó là một kịch bản csh.
sch

2

1) Shell hiện tại bạn đang chạy. (Bất kỳ shell nào có thể)

2) Dán cùng loại vỏ (bash / dash / ash / csh / bất kể hương vị của bạn) và đảm bảo "nền tảng được hỗ trợ" của bạn cài đặt vỏ bạn muốn sử dụng theo mặc định. Ngoài ra, hãy thử sử dụng các lệnh phổ biến có sẵn trên các hệ thống. Tránh các tùy chọn máy cụ thể.

3) Không thực sự có logic "nếu-thì-khác" đối với interpreter directive. Bạn nên chỉ định một shell nên tồn tại trên tất cả các hệ thống mà bạn muốn hỗ trợ ... tức là #!/bin/bashhoặc chỉ định một chung chung #!/bin/shmiễn là tập lệnh của bạn khá chung chung trên tất cả các shell.

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.