Tôi đang làm việc với một tập lệnh shell xây dựng một lệnh phức tạp từ các biến, ví dụ như thế này (với một kỹ thuật mà tôi đã học được từ Câu hỏi thường gặp của Bash ):
#!/bin/bash
SOME_ARG="abc"
ANOTHER_ARG="def"
some_complex_command \
${SOME_ARG:+--do-something "$SOME_ARG"} \
${ANOTHER_ARG:+--with "$ANOTHER_ARG"}
Kịch bản này tự động thêm các thông số --do-something "$SOME_ARG"
và --with "$ANOTHER_ARG"
để some_complex_command
nếu các biến được định nghĩa. Cho đến nay điều này là làm việc tốt.
Nhưng bây giờ tôi cũng muốn có thể in hoặc ghi nhật ký lệnh khi tôi đang chạy nó, ví dụ như khi tập lệnh của tôi chạy ở chế độ gỡ lỗi. Vì vậy, khi tập lệnh của tôi chạy some_complex_command --do-something abc --with def
, tôi cũng muốn có lệnh này bên trong một biến để tôi có thể đăng nhập nó vào syslog.
Câu hỏi thường gặp về Bash thể hiện một kỹ thuật sử dụng DEBUG
bẫy và $BASH_COMMAND
biến (ví dụ cho mục đích gỡ lỗi) cho mục đích này. Tôi đã thử điều đó với đoạn mã sau:
#!/bin/bash
ARG="test string"
trap 'COMMAND="$BASH_COMMAND"; trap - DEBUG' DEBUG
echo "$ARG"
echo "Command was: ${COMMAND}"
Điều này hoạt động, nhưng nó không mở rộng các biến trong lệnh:
host ~ # ./test.sh
test string
Command was: echo "$ARG"
Tôi đoán tôi phải sử dụng eval để mở rộng echo "$ARG"
tới echo test string
(ít nhất tôi đã không tìm thấy một cách mà không eval
được nêu ra). Sau đây không hoạt động:
eval echo "Command was: ${COMMAND}"
Nó tạo ra đầu ra sau:
host ~ # ./test.sh
test string
Command was: echo "$ARG"
Command was: echo test string
Nhưng tôi không thực sự chắc chắn nếu tôi có thể sử dụng eval
một cách an toàn như thế này. Tôi đã không thành công khi cố gắng khai thác một số thứ:
#!/bin/bash
ARG="test string; touch /x"
DANGER='$(touch /y; cat /etc/shadow)'
trap 'COMMAND="$BASH_COMMAND"; trap - DEBUG' DEBUG
echo "$ARG" $DANGER
echo "Command was: ${COMMAND}"
eval echo "Command was: ${COMMAND}"
Có vẻ như xử lý việc này tốt, nhưng tôi tò mò nếu ai đó thấy vấn đề mà tôi đã bỏ qua.