Một vài lưu ý khi sử dụng Shell Script (phần 2)
Bài đăng này đã không được cập nhật trong 8 năm
Phần trước: Một vài lưu ý khi sử dụng Shell Script (phần 1)
II. Nghĩ lại về shebang
Có phải bạn đang sử dụng #!/bin/{bash,zsh,sh}
ở dòng shebang? Hầu hết những script files mà tôi phải làm việc đều chứa dòng shebang như vậy, và nó thật tệ.
Hãy để tôi phân tích tại sao chúng ta nên sử dụng #!/usr/bin/env {bash,zsh,sh}
thay thế cho #!/bin/{bash,zsh,sh}
.
Tại sao /bin/bash
lại không tốt?
Đầu tiên, câu lệnh trên đòi hỏi bash
(hay bất cứ chương trình nào bạn đang sử dụng) phải được cài đặt ở một vị trí cố định tại tất cả các hệ thống mà script được chạy. Mặc dù điều này hầu hết là đúng, nhưng ko phải là ko có ngoại lệ. Tại OpenBSD, bash
chỉ là một optional package, và được đặt ở /usr/local/bin/bash
.
Ngay cả khi bạn sử dụng hệ thống mà bash
được cài đặt ở bin/bash
thì cũng sẽ có thể có nhiều phiên bản bash
khác nhau được cài đặt ở nhiều vị trí khác nhau.
$ bash --version
version 4.3.33
$ /bin/bash --version
version 3.2.51
Điều này xảy ra khi tôi sử dụng homebrew
để cài đặt version mới nhất của bash
, mà tất cả các homebrew packages lại được cài đặt ở /usr/local/bin/
. Nếu script muốn sử dụng phiên bản bash 4, lại sử dụng shebang như trên thì sẽ phát sinh lỗi do bị chỉ định chạy bằng bash 3.
Hãy sử dụng $PATH
Tại sao /usr/bin/env
lại giải quyết được vấn đề?
Bởi vì thay vì hard-coding một vị trí, script sẽ tìm kiếm bash
trong $PATH
của hệ thống. Điều đó có nghĩa rằng bash
ở đâu không quan trọng, có nhiều hơn một version cũng không thành vấn đề, miễn là nó ở trong $PATH
.
$ export PATH=/bin/:$PATH
$ /usr/bin/env bash --version
version 3.2.51
$ export PATH=/usr/local/bin:$PATH
$ /usr/bin/env bash --version
version 4.3.33
Vấn đề bảo mật
Giờ chúng ta đã thấy rằng nên sử dụng $PATH
để tìm kiếm chương trình mà chúng ta muốn chạy, tuy nhiên bên cạnh đó cũng sẽ phát sinh vấn đề bảo mật cần phải lưu ý khi thực thi trong môi trường multi-user.
Ví dụ tôi sẽ tạo ra một đoạn script độc tại /home/kanamikiii/evil/bash
và bằng cách nào đó lừa bạn thêm nó vào path của bạn (export PATH=/home/kanamikiii/evil/ :$PATH
). Khi đó mỗi khi bạn thực thi, env
sẽ tìm kiếm bash
trong $PATH
của bạn và chạy đoạn script của tôi.
Vấn đề tương thích
Bên cạnh đó, còn một vấn đề xảy ra mà bạn cần quan tâm khi sử dụng /usr/bin/env
.
Một vài hệ thống chỉ cho phép xử lý shebang với một interpreter và một đối số. Điều đó có nghĩa là khi bạn muốn chạy Ruby ở warning mode, sử dụng #!/usr/bin/env ruby -w
sẽ phát sinh lỗi. Lúc này env
là interpreter, ruby
là đối số, và -w
sẽ bị parse như một tên file.
Tổng kết
- Trong hầu hết các trường hợp, sử dụng
/usr/bin/env bash
sẽ tốt hơn/bin/bash
. - Nếu bạn đang chạy ở môi trường multi-user và vấn đề bảo mật cần đề cao, đừng sử dụng
/usr/bin/env
(hay bất cứ thứ j dùng đến$PATH
). - Nếu bạn cần thêm các đối số cho interpreter,
/usr/bin/env
có thể khiến bạn phải đắn đo đấy.
Source: Rethinking your shebang
All rights reserved