12/08/2018, 13:41

Một vài lưu ý khi sử dụng Shell Script (phần 2)

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 ...

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

0