Câu trả lời:
sudo su -
, đó là một cách viết phức tạp sudo -i
, xây dựng một môi trường nguyên sơ. Đó là điểm của một vỏ đăng nhập. Ngay cả một đồng bằng sudo
loại bỏ hầu hết các biến từ môi trường. Hơn nữa sudo
là một lệnh bên ngoài; không có cách nào để nâng cao các đặc quyền trong chính tập lệnh shell, chỉ chạy một chương trình bên ngoài ( sudo
) với các đặc quyền bổ sung và điều đó có nghĩa là bất kỳ biến shell nào (tức là các biến không xuất) và các hàm được xác định trong shell cha sẽ không khả dụng trong Vỏ con.
Bạn có thể chuyển các biến môi trường thông qua bằng cách không gọi shell đăng nhập ( sudo bash
thay vì sudo su -
hoặc sudo -i
) và định cấu hình sudo để cho các biến này đi qua (có Defaults !env_reset
hoặc Defaults env_keep=…
trong sudoers
tệp). Điều này sẽ không giúp bạn cho các chức năng (mặc dù bash có một cơ sở xuất khẩu chức năng, sudo chặn nó).
Cách thông thường để có được các chức năng của bạn trong shell con sẽ là xác định chúng ở đó. Hãy cẩn thận khi trích dẫn: nếu bạn sử dụng <<EOF
cho tài liệu ở đây, nội dung của tài liệu ở đây trước tiên được mở rộng bởi trình bao cha mẹ và kết quả của việc mở rộng đó trở thành tập lệnh mà trình bao con nhìn thấy. Đó là, nếu bạn viết
sudo -u "$target_user" -i <<EOF
echo "$(whoami)"
EOF
Điều này sẽ hiển thị tên của người dùng ban đầu, không phải người dùng đích. Để tránh giai đoạn mở rộng đầu tiên này, hãy trích dẫn tài liệu đánh dấu ở đây sau <<
toán tử:
sudo -u "$target_user" -i <<'EOF'
echo "$(whoami)"
EOF
Vì vậy, nếu bạn không cần truyền dữ liệu từ shell cha sang shell con, bạn có thể sử dụng tài liệu được trích dẫn ở đây:
#!/bin/bash
sudo -u "$target_user" -i <<'EOF'
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f "${intVAR}"
EOF
Mặc dù bạn có thể sử dụng một điểm đánh dấu tài liệu không được trích dẫn ở đây để truyền dữ liệu từ vỏ cha sang vỏ con, nhưng điều này chỉ hoạt động nếu dữ liệu không chứa bất kỳ ký tự đặc biệt nào. Đó là bởi vì trong một kịch bản như
sudo -u "$target_user" -i <<EOF
echo "$(whoami)"
EOF
đầu ra whoami
trở thành một bit của mã shell, không phải là một chuỗi. Ví dụ, nếu whoami
lệnh trả về "; rm -rf /; "true
thì shell con sẽ thực thi lệnh echo ""; rm -rf /; "true"
.
Nếu bạn cần truyền dữ liệu từ shell cha, một cách đơn giản là truyền nó dưới dạng đối số. Gọi shell con một cách rõ ràng và truyền cho nó các tham số vị trí:
#!/bin/bash
extVAR="yourName"
sudo -u "$target_user" -i sh _ "$extVAR" <<'EOF'
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f "${intVAR}" "${1}"
EOF
Nếu bạn có nhiều biến để vượt qua, việc chuyển chúng theo tên sẽ dễ đọc hơn. Gọi env
rõ ràng để đặt các biến môi trường cho shell con.
#!/bin/bash
extVAR="yourName"
sudo -u "$target_user" -i env extVAR="$extVAR" sh <<'EOF'
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f "${intVAR}" "${1}"
EOF
Lưu ý rằng nếu bạn mong muốn /etc/profile
và người dùng mục tiêu ~/.profile
sẽ được đọc, bạn sẽ phải đọc chúng một cách rõ ràng hoặc gọi bash --login
thay vì sh
.
Điều này không hoạt động vì chức năng log_f
không được khai báo trong trình sudo su -
bao bạn khởi chạy. Thay thế:
extVAR="yourName"
sudo su - <user> << EOF
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f ${intVAR} ${extVAR}
EOF
Bạn cần lấy hàm được định nghĩa trong lớp con gốc. Điều đó có thể làm điều đó, nhưng .... tôi không biết hầu hết những thứ đó làm gì. Ít nhất - miễn là không phải sudo
và cũng không su
yêu cầu stdin để đọc một mật khẩu - đó nên được log_f()
công bố.
Tôi tin rằng bạn có nghĩa là mở rộng các giá trị đó vào đầu vào của vỏ gốc. Nếu bạn không có ý định làm như vậy thì bạn nên trích dẫn EOF
và chính họ.
Trong trường hợp của tôi, tôi cần truyền một mảng vào và gặp một số rắc rối, nhưng sau một thời gian đã thành công bằng cách lặp lại các giá trị của mảng thành một env
-key và gói mã dự định vào bash -c '<intended code>'
, và về cơ bản nó sẽ tái tạo mảng, ví dụ : INNER_KEY=($<env_key>)
.
Đối với đề thi:
#!/usr/bin/env bash
PLUGINS=(foo bar baz)
sudo -u <some-user> -i env PLUGINS="`echo ${PLUGINS[@]}`" sh <<'EOF'
bash -c '
FOO=($PLUGINS);
echo values: \[${FOO[@]}\];
for pl in ${FOO[@]};
do echo value: $pl;
done;
'
EOF
Vấn đề là tôi không thể trực tiếp làm điều gì đó như sau (không sử dụng bash -c '...'
):
FOO=($PLUGINS);
for pl in ${FOO[@]};
...