Làm thế nào để bắt đầu một kịch bản với môi trường sạch?


15

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ìm thấy những câu hỏi tương tự nhưng không chỉ ra cách làm từ shebang
balki

5
Bạn không thể làm điều đó từ shebang. Các shebang chỉ có thể chấp nhận một arg.
jordanm

Câu trả lời:


7

Lý do điều này không hoạt động là vì nó được xem -i /bin/shnhư là một đối số duy nhất env. Thông thường đây sẽ là 2 đối số, -i/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 CLEANEDbiế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.


envtừ 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.
Weijun Zhou

Vừa thử. Nó hoạt động cho câu hỏi ban đầu là tốt. Chỉ cần sử dụng #!/usr/bin/env -S -i /bin/sh. Hãy nhận biết các vấn đề di động.
Weijun Zhou

3

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 execkhi môi trường không sạch (ví dụ: $ HOME được xác định):

[ "$HOME" != "" ] && exec -c $0

Đẹp. Đừng làm env -i bash như tôi đã làm và sau đó tự hỏi tại sao các biến env của bạn vẫn được đặt (tất nhiên là bash resource .bashrc và những người bạn 8)
Neil McGill

2

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 -eset -ulệ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 -ecài đặt.

Việc kiểm tra HOMEbiế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"

0

$ cat script.sh

#!/bin/env -i /bin/sh

Đáng buồn thay, nó sẽ không hoạt động theo cách đó - Linux thực sự coi -i /bin/shlà một đối số được chuyển đến env(xem Shebang ).


0

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 perlvớ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ố. perlLogic 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_SIZEký 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: - /

perlxử 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, @ARGVthường chỉ chứa các đối số, và $0có 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-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 ksh93thực hiện:

#!/bin/ksh /usr/bin/env -i /bin/sh

mặc dù có lẽ kshkhông phổ biến như ngày nay ;-)

( bashcó 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 execcá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à unsets 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.

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.