Tôi đã thử cách sau nhưng có vẻ không hiệu quả:
$ cat script.sh
#!/bin/env -i /bin/sh
/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.
Tôi đã thử cách sau nhưng có vẻ không hiệu quả:
$ cat script.sh
#!/bin/env -i /bin/sh
/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.
Câu trả lời:
Lý do điều này không hoạt động là vì nó được xem -i /bin/sh
như là một đối số duy nhất env
. Thông thường đây sẽ là 2 đối số, -i
và /bin/sh
. Đây chỉ là một hạn chế của shebang. Không có cách nào xung quanh nó.
Tuy nhiên bạn vẫn có thể thực hiện nhiệm vụ này, chỉ là một cách khác.
Nếu bạn muốn tác vụ này được thực hiện bởi chính tập lệnh và không phải thực hiện một thao tác nào đó env -i script.sh
, bạn có thể thực hiện lại tập lệnh.
#!/bin/sh
[ -z "$CLEANED" ] && exec /bin/env -i CLEANED=1 /bin/sh "$0" "$@"
Điều này sẽ khiến tập lệnh tự thực thi lại nếu CLEANED
biến môi trường không được đặt. Sau đó, khi thực hiện lại, nó đặt biến để đảm bảo rằng nó không đi vào một vòng lặp.
env
từ lõi GNU bây giờ có một tùy chọn -S
để giải quyết các vấn đề tương tự như vấn đề này nhưng không hoàn toàn giống nhau. Ví dụ #!/usr/bin/env -S perl -T
.
#!/usr/bin/env -S -i /bin/sh
. Hãy nhận biết các vấn đề di động.
Chạy tập lệnh của bạn với env -i
:
env -i script.sh
Và kịch bản như bình thường:
#!/bin/sh
# ... your code here
Nếu bạn có nghĩa là chạy với một môi trường sạch mà không nói rõ ràng rằng khi bạn chạy. Eduardo Ivanec đưa ra một số ý tưởng trong câu trả lời này , bạn có thể gọi đệ quy tập lệnh của mình exec
khi môi trường không sạch (ví dụ: $ HOME được xác định):
[ "$HOME" != "" ] && exec -c $0
Với bash, bạn có thể làm như thế này:
#!/usr/bin/bash
set -e
set -u
[ -v HOME ] && exec -c "$0" "$@"
# continue with the rest of the script
# e.g. print the cleaned environment:
export
Các lệnh set -e
và set -u
lệnh không thực sự cần thiết, nhưng tôi bao gồm chúng để chứng minh rằng phương pháp này không phụ thuộc vào việc truy cập các biến không đặt (ví dụ như [ "$HOME" != "" ]
) và tương thích với một set -e
cài đặt.
Việc kiểm tra HOME
biến phải an toàn vì bash thực thi các tập lệnh ở chế độ không tương tác, tức là các tệp cấu hình như ~/.bashrc
(nơi có thể đặt biến môi trường) không có nguồn gốc trong khi khởi động.
Ví dụ đầu ra:
declare -x OLDPWD
declare -x PWD="/home/juser"
declare -x SHLVL="1"
Giới hạn shebang đối số Linux 2 (interpeter + đối số đơn) được ghi chú trong hầu hết các câu trả lời, nhưng để nói điều này không thể thực hiện được là không chính xác - bạn chỉ cần thay đổi thành trình thông dịch có thể làm điều gì đó hữu ích với một đối số duy nhất:
#!/usr/bin/perl -we%ENV=();exec "/bin/sh " . join " ", map "'$_'", @ARGV;
# your sh script here
Những gì nó làm được gọi perl
với một kịch bản một lớp ( -e
) sẽ xóa %ENV
(rẻ hơn env -i
) và gọi exec /bin/sh
, trích dẫn chính xác các đối số. perl
Logic hơn nữa có thể được thêm vào, nếu được yêu cầu (mặc dù không nhiều trên Linux vì bạn bị giới hạn ở các BINPRM_BUF_SIZE
ký tự, có khả năng là 128)
Đáng buồn thay, đây là Linux cụ thể, nó sẽ không hoạt động trên một hệ thống cho phép nhiều đối số shebang: - /
perl
xử lý chuỗi này dưới dạng một đối số duy nhất, do đó, nó không được trích dẫn ở trên như bạn thường làm với perl -e ...
dòng lệnh (nếu bạn thêm dấu ngoặc kép được giữ nguyên, perl chỉ thấy một chuỗi ký tự, với cảnh báo về nó sẽ phàn nàn về một chuỗi vô dụng không thay đổi).
Cũng lưu ý có một thay đổi nhỏ trong hành vi khi được sử dụng theo cách này, @ARGV
thường chỉ chứa các đối số, và $0
có chứa các kịch bản, nhưng với công việc này $ARGV[0]
là tên của kịch bản (và $0
là -e
) mà làm cho nó một chút dễ dàng hơn.
Bạn cũng có thể giải quyết vấn đề này với một trình thông dịch "xử lý lại" dòng lệnh của nó (không có -c
đối số phụ ) mà AT & T cổ đại ksh93
thực hiện:
#!/bin/ksh /usr/bin/env -i /bin/sh
mặc dù có lẽ ksh
không phổ biến như ngày nay ;-)
( bash
có một tính năng tương tự --wordexp
, nhưng nó "không có giấy tờ" trong các phiên bản mà nó hoạt động và không được bật vào thời gian biên dịch trong các phiên bản được ghi lại: - / Nó cũng không thể được sử dụng cho điều này vì nó cần hai đối số. ..)
Ngoài ra, thực sự là một biến thể của câu trả lời của @Patrick và @ maxschlepzig:
#!/bin/bash
[ "$_" != bash ] && exec -c -a "bash" /bin/bash "$0" "$@"
# your script here
Thay vì sử dụng một biến mới, điều này sử dụng _
biến " " đặc biệt , nếu nó không được đặt thành "bash" chính xác thì hãy thay thế tập lệnh bằng exec
cách sử dụng -a
để tạo ARGV[0]
(và do đó $_
) chỉ là "bash" và sử dụng -c
để xóa môi trường.
Ngoài ra, nếu chấp nhận làm sạch môi trường khi bắt đầu tập lệnh (chỉ bash):
#!/bin/sh
unset $(compgen -e)
# your script here
Điều đó sử dụng compgen
(trình trợ giúp hoàn thành) để liệt kê tên của tất cả các biến môi trường được xuất và unset
s chúng trong một lần.
Xem thêm Nhiều đối số trong shebang để biết thêm chi tiết về vấn đề chung về hành vi của shebang.