Thật tốt khi có bình luận không chính xác cuối cùng để sửa nó, nhưng ngay sau đó, nó trở thành rác có thể gây nhầm lẫn.
Cách tiếp cận của tôi là hai bước: lưu trữ các lệnh thất bại khi chúng thực hiện và loại bỏ chúng sau đó.
Lưu trữ các lệnh thất bại khi chúng thực hiện:
error_handler() {
FAILED_COMMANDS="$(history | tail -1l | cut -c -5) $FAILED_COMMANDS"
}
trap error_handler ERR
trap command signals
thực thi command
khi một trong số đó signals
được "nâng lên".
$(command)
, thực hiện command
và nắm bắt đầu ra của nó.
Khi lệnh thất bại, đoạn mã này sẽ ghi lại số lịch sử của lệnh cuối cùng được lưu vào lịch sử và lưu trữ nó trong biến để xóa trong tương lai.
Đơn giản, nhưng hoạt động không chính xác với HISTCONTROL
và HISTIGNORE
- khi lệnh không được lưu vào lịch sử do một trong các biến, số lịch sử của lệnh cuối cùng được lưu vào lịch sử là lệnh trước đó; vì vậy, nếu lệnh không chính xác không được lưu vào lịch sử, lệnh trước đó sẽ bị xóa.
Phiên bản phức tạp hơn một chút, hoạt động chính xác trong trường hợp đó:
debug_handler() {
LAST_COMMAND=$BASH_COMMAND;
}
error_handler() {
local LAST_HISTORY_ENTRY=$(history | tail -1l)
# if last command is in history (HISTCONTROL, HISTIGNORE)...
if [ "$LAST_COMMAND" == "$(cut -d ' ' -f 2- <<< $LAST_HISTORY_ENTRY)" ]
then
# ...prepend it's history number into FAILED_COMMANDS,
# marking the command for deletion.
FAILED_COMMANDS="$(cut -d ' ' -f 1 <<< $LAST_HISTORY_ENTRY) $FAILED_COMMANDS"
fi
}
trap error_handler ERR
trap debug_handler DEBUG
Loại bỏ các lệnh được lưu trữ sau đó:
exit_handler() {
for i in $(echo $FAILED_COMMANDS | tr ' ' '\n' | uniq)
do
history -d $i
done
FAILED_COMMANDS=
}
trap exit_handler EXIT
Giải trình:
Khi thoát Bash, đối với mỗi số lịch sử duy nhất sẽ xóa mục nhập lịch sử tương ứng,
sau đó xóa FAILED_COMMANDS
để không xóa các lệnh kế thừa số lịch sử khỏi các lệnh đã bị xóa.
Nếu bạn chắc chắn rằng nó FAILED_COMMANDS
sẽ không bị trùng lặp, bạn có thể lặp lại đơn giản trên nó
(tức là viết for i in $FAILED_COMMANDS
). Tuy nhiên, nếu bạn hy vọng nó không được sắp xếp từ lớn nhất đến nhỏ nhất (trong trường hợp này luôn luôn như vậy), hãy thay thế uniq
bằng sort -rnu
.
Các số trong lịch sử FAILED_COMMANDS
phải là duy nhất và được sắp xếp từ lớn nhất đến nhỏ nhất, bởi vì khi bạn xóa mục nhập, các số của lệnh tiếp theo sẽ bị dịch chuyển - tức là. Khi bạn phát hành history -d 2
, mục thứ 3 trở thành thứ 2, thứ 4 trở thành thứ 3, v.v.
Do đó, khi sử dụng mã này, bạn không thể gọi thủ công history -d <n>
ở nơi n
nhỏ hơn hoặc bằng số lớn nhất được lưu trữFAILED_COMMANDS
và mong muốn mã hoạt động chính xác.
Đây có thể là ý tưởng tốt để treo exit_handler
tại EXIT
, nhưng bạn cũng có thể gọi bất cứ lúc nào trước đó.