Câu trả lời:
Sử dụng fc
để có được dòng lệnh trước đó. Nó thường được sử dụng để chỉnh sửa dòng lệnh trước đó trong trình soạn thảo yêu thích của bạn, nhưng nó cũng có chế độ "danh sách":
last_command="$(fc -nl -1)"
caller
và các mảng bash BASH_LINENO
, BASH_SOURCE
và FUNCNAME
để làm một loại vết đống.
Nếu lệnh cuối cùng được thực thi mà không có đối số, nó sẽ được lưu trong $_
biến. Điều này thường chứa đối số cuối cùng của lệnh trước - vì vậy nếu không có đối số, giá trị của $_
chính nó là lệnh cuối cùng.
Một lựa chọn khác là tìm hiểu các chi tiết của lệnh nền cuối cùng . Như l0b0 đã viết, $!
giữ PID của nó - vì vậy bạn có thể phân tích đầu ra của ps $!
(có thể với các tùy chọn định dạng bổ sung thành ps
).
Không, nhưng bạn có thể lấy nó trong khi thực thi để lưu trữ các lệnh khác:
$0
: Đường dẫn của tập lệnh shell hiện tại.$FUNCNAME
: "Tên của hàm hiện tại.""$@"
: Tất cả các tham số của lệnh hiện tại, được trích dẫn riêng.$!
: "PID (ID tiến trình) của công việc cuối cùng chạy trong nền."$$
: "ID tiến trình (PID) của chính tập lệnh."Do đó, lệnh đầy đủ của tập lệnh hiện tại phải là "$0" "$@"
. Nếu đó là một chức năng thì nó phải như vậy "$FUNCNAME" "$@"
. Bạn có thể muốn lưu trữ nó trong một mảng để xử lý trong tương lai. Ví dụ: lưu trữ này trong test.sh
:
#!/usr/bin/env bash
foo()
{
declare -a command=("$0")
for param in "$@"
do
command+=("$(printf %q "$param")")
done
echo "${command[@]}"
}
foo "$@"
Khi chạy ./test.sh "first argument" "second argument"
, nó sẽ trở lại:
./test.sh first\ argument second\ argument
Đó là những cuộc gọi tương đương.
BASH_COMMAND
biến, nhưng dường như không hữu ích theo bất kỳ cách nào, ngoài việc sử dụng trong bẫy.
some-command
trong một kịch bản shell, và nó thất bại. Tôi sẽ có trạng thái khác không $?
, liệu "không" có còn tồn tại cho sự tồn tại của việc giữ biến some-command
không?
Cái DEBUG
bẫy cho phép bạn thực thi một lệnh ngay trước khi thực hiện lệnh đơn giản. Một phiên bản chuỗi của lệnh để thực thi (với các từ được phân tách bằng dấu cách) có sẵn trong BASH_COMMAND
biến.
trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG
…
echo "last command is $previous_command"
Lưu ý rằng previous_command
sẽ thay đổi mỗi khi bạn chạy một lệnh, vì vậy hãy lưu nó vào một biến để sử dụng nó. Nếu bạn cũng muốn biết trạng thái trả về của lệnh trước đó, hãy lưu cả hai trong một lệnh.
cmd=$previous_command ret=$?
if [ $ret -ne 0 ]; then echo "$cmd failed with error code $ret"; fi
Nếu bạn chỉ muốn hủy bỏ một lệnh thất bại, hãy sử dụng set -e
để thoát tập lệnh của bạn trên lệnh thất bại đầu tiên. Bạn có thể hiển thị lệnh cuối cùng từ EXIT
bẫy .
set -e
trap 'echo "exit $? due to $previous_command"' EXIT
Một cách tiếp cận khác có thể có hiệu quả đối với một số mục đích sử dụng là sử dụng set -x
để in dấu vết thực thi của tập lệnh và kiểm tra một vài dòng cuối cùng của dấu vết.
Tôi thấy cần phải tìm lệnh thất bại cuối cùng khi có set -e
và set -o pipefail
các tùy chọn, vì nếu không thì bash chỉ đơn giản là hủy bỏ mà không có phản hồi về lý do, vì vậy đây là điều tôi thấy hoạt động tốt:
#!/usr/bin/env bash
set -eu
set -o pipefail
cur_command=
first_err_command=
first_err_lineno=
# This trap is executed in exactly the same conditions in which the `set -e` results in an exit.
trap 'cur_command=$BASH_COMMAND;
if [[ -z "$first_err_command" ]]; then
first_err_command=$cur_command;
first_err_lineno=$LINENO;
fi' ERR
trap 'if [[ ! -z "$first_err_command" ]]; then
echo "ERROR: Aborting at line: $first_err_lineno on command: $first_err_command";
fi' EXIT
echo "The following command causes bash to abort, but it should also result in a nice message"
false
echo "This message is not expected"
Nếu bạn chạy ở trên, cuối cùng bạn sẽ thấy loại đầu ra bên dưới:
The following command causes bash to abort, but it should also result in a nice message
ERROR: Aborting at line: 22 on command: false
Số dòng có thể không phải lúc nào cũng chính xác, nhưng nó sẽ cung cấp cho bạn một cái gì đó đủ gần để hữu ích.