Tại sao tập lệnh này hoạt động trong thiết bị đầu cuối mà không phải từ một tập tin?


18

Tôi có tập lệnh shell này được lưu trong một tập tin: nó thực hiện một số thay thế chuỗi cơ bản.

#!/bin/sh
html_file=$1
echo "html_file = $html_file"
substr=.pdf
pdf_file="${html_file/.html/.pdf}"
echo "pdf_file = $pdf_file"

Nếu tôi dán nó vào dòng lệnh, nó hoạt động tốt:

$ html_file="/home/max/for_pauld/test_no_base64.html"
  echo "html_file = $html_file"
  substr=.pdf
  pdf_file="${html_file/.html/.pdf}"
  echo "pdf_file = $pdf_file"

cho

html_file = /home/max/for_pauld/test_no_base64.html
pdf_file = /home/max/for_pauld/test_no_base64.pdf

Đó là đầu ra từ echo ở trên - nó hoạt động như dự định.

Nhưng, khi tôi gọi kịch bản, với

$ saucer "/home/max/for_pauld/test_no_base64.html"

Tôi nhận được kết quả này:

html_file = /home/max/for_pauld/test_no_base64.html
/home/max/bin/saucer: 5: /home/max/bin/saucer: Bad substitution

Là kịch bản của tôi sử dụng một phiên bản khác của bash hoặc một cái gì đó? Tôi có cần thay đổi dòng shebang của tôi?


6
Sự mở rộng tham số đó là một bashism (tốt, không phải POSIX): thay đổi shebang của bạn.
jasonwryan

Cảm ơn! Điều đó đã làm việc. Tôi nghĩ rằng tôi có một chút mơ hồ về sự khác biệt giữa shbash. Tôi sẽ đọc nó. Nếu bạn có thể bận tâm để đưa ra nhận xét của bạn thành một câu trả lời thì tôi sẽ đánh dấu nó chính xác.
Max Williams

Đã đánh dấu vào The Duke cho câu trả lời chi tiết của mình, nhưng dù sao cũng cảm ơn.
Max Williams

2
@MaxWilliams: tóm lại, sh là vỏ bourne ban đầu. Tất cả các kịch bản tương thích nên được viết cho sh. Nhưng nhiều shell tiếp theo (ví dụ: bash, Bourne Again shell) "gần như tương thích" và thêm rất nhiều tính độc đáo. Chẳng hạn như sự thay thế bạn đã sử dụng. Ngày nay, bạn khá an toàn khi chỉ sử dụng các tính năng posix, nhưng lưu ý rằng tính di động phụ thuộc vào ngay cả một bộ hẹp hơn (tức là chỉ sh). Vì vậy, nói chung, sử dụng: #!/usr/bin/env bashnhư shebang của bạn, và sử dụng thay thế được xác định rõ ràng như bạn muốn, nhưng với sự cẩn thận tính di động. Và đọc: unix.stackexchange.com/a/48787/27616
Olivier Dulac

Câu trả lời:


36

Sh là gì

sh(hoặc Ngôn ngữ lệnh Shell) là ngôn ngữ lập trình được mô tả theo tiêu chuẩn POSIX . Nó có nhiều triển khai ( ksh88, dash, ...). bashcũng có thể được coi là một thực hiện sh(xem bên dưới).

Bởi vì shlà một đặc tả, không phải là một triển khai, /bin/shlà một liên kết tượng trưng (hoặc một liên kết cứng) với một triển khai thực tế trên hầu hết các hệ thống POSIX.

Bash là gì

bashbắt đầu như một shtriển khai tương thích (mặc dù nó có trước tiêu chuẩn POSIX vài năm), nhưng khi thời gian trôi qua, nó đã có được nhiều phần mở rộng. Nhiều tiện ích mở rộng này có thể thay đổi hành vi của tập lệnh shell POSIX hợp lệ, do đó, bản thân nó bashkhông phải là trình bao POSIX hợp lệ. Thay vào đó, nó là một phương ngữ của ngôn ngữ shell POSIX.

bashhỗ trợ một --posixcông tắc, làm cho nó phù hợp hơn với POSIX. Nó cũng cố gắng bắt chước POSIX nếu được gọi là sh.

sh = bash?

Trong một thời gian dài, /bin/shđược sử dụng để trỏ đến /bin/bashhầu hết các hệ thống GNU / Linux. Kết quả là, nó gần như trở nên an toàn khi bỏ qua sự khác biệt giữa hai người. Nhưng điều đó đã bắt đầu thay đổi gần đây.

Một số ví dụ phổ biến về các hệ thống /bin/shkhông trỏ đến /bin/bash(và trên một số trong đó /bin/bashcó thể không tồn tại) là:

  1. Các hệ thống Debian và Ubuntu hiện đại, theo mặc định symlink shđến dash;
  2. Busybox , thường được chạy trong thời gian khởi động hệ thống Linux như là một phần của initramfs. Nó sử dụng ashthực hiện shell.
  3. BSD và nói chung bất kỳ hệ thống không phải Linux nào. OpenBSD sử dụng pdksh, hậu duệ của vỏ Korn. FreeBSD shlà hậu duệ của vỏ UNIX Bourne ban đầu. Solaris có cái riêng shmà trong một thời gian dài không tuân thủ POSIX; một triển khai miễn phí có sẵn từ dự án Gia truyền .

Làm thế nào bạn có thể tìm ra những /bin/shđiểm trên hệ thống của bạn?

Sự phức tạp là đó /bin/shcó thể là một liên kết tượng trưng hoặc một liên kết cứng. Nếu đó là một liên kết tượng trưng, ​​một cách di động để giải quyết nó là:

% file -h /bin/sh
/bin/sh: symbolic link to bash

Nếu đó là một liên kết cứng, hãy thử

% find -L /bin -samefile /bin/sh
/bin/sh
/bin/bash

Trên thực tế, -Lcờ bao trùm cả symlink và hardlink, nhưng nhược điểm của phương pháp này là nó không khả dụng - POSIX không yêu cầu find hỗ trợ -samefiletùy chọn, mặc dù cả GNU findFreeBSD đều hỗ trợ nó.

Dòng Shebang

Cuối cùng, tùy bạn quyết định sử dụng cái nào, bằng cách viết dòng «shebang».

Ví dụ

#!/bin/sh

sẽ sử dụng sh(và bất cứ điều gì xảy ra để chỉ đến),

#!/bin/bash

sẽ sử dụng /bin/bashnếu nó khả dụng (và không thành công với thông báo lỗi nếu không có). Tất nhiên, bạn cũng có thể chỉ định thực hiện khác, ví dụ:

#!/bin/dash

Cái nào dùng

Đối với các tập lệnh của riêng tôi, tôi thích shvì những lý do sau:

  • nó được chuẩn hóa
  • nó đơn giản và dễ học hơn nhiều
  • nó có thể di động trên các hệ thống POSIX - ngay cả khi chúng không có bash, chúng bắt buộc phải cósh

Có những lợi thế để sử dụng bashlà tốt. Các tính năng của nó làm cho lập trình thuận tiện hơn và tương tự như lập trình trong các ngôn ngữ lập trình hiện đại khác. Chúng bao gồm những thứ như các biến cục bộ và mảng. Plain shlà một ngôn ngữ lập trình rất tối giản.


Cảm ơn câu trả lời chi tiết: Tôi sử dụng Linux Mint dựa trên Debian và /bin/shthực sự là một liên kết tượng trưng /bin/dash.
Max Williams

Nếu bạn muốn tuân thủ POSIX sh, thì tốt nhất hãy bỏ hoàn toàn shebang: Nếu dòng đầu tiên của tệp lệnh shell bắt đầu bằng các ký tự "#!", Kết quả là pubs.opengroup.org/onlinepub/009695399/ tiện ích / Tập
Daniel Jour

4
@DanielJour Nếu bất kỳ hệ thống nào giống Unix bỏ đi sự hỗ trợ thông thường cho các shebang, nó sẽ phá vỡ rất nhiều thứ mà thực tế nó không thể sử dụng được. Vì vậy, nó là một tiêu chuẩn thực tế, ngay cả khi nó không được chỉ định trong POSIX. Vấn đề tương thích thực tế duy nhất là đường dẫn đến thông dịch viên có thể khác nhau.
Barmar

23

Thêm vào câu trả lời xuất sắc từ @ Hunter.S.Thndry Tôi muốn chỉ ra rằng phần không thể di động của tập lệnh là

pdf_file="${html_file/.html/.pdf}"

Đây ${variable/search/replace}là một phần mở rộng GNU. Nhưng bạn có thể dễ dàng tránh nó với POSIX thuần túy:

pdf_file="${html_file%.html}".pdf

Theo Hunter, đây là cách khắc phục tốt hơn thay đổi shebang thành #! /bin/bash


Cảm ơn - Tôi đồng ý rằng đó là bản sửa lỗi "tinh khiết" hơn nhưng tôi thích sử dụng bash shebang hơn, vì bash là thứ tôi thường sử dụng trong thiết bị đầu cuối (theo mặc định) và các tập lệnh chỉ làm điều tương tự như thông thường dòng lệnh.
Max Williams

1
@MaxWilliams Tất nhiên, không vấn đề gì. Điều này chủ yếu được dành cho cơ sở dữ liệu Q & A.
Philippos
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.