我想要一个 bash 脚本来实现 bash 命令行本身的一些功能:即命令历史记录和 vi 风格的命令编辑。
该脚本将永远循环(直到 crtl/d)并在终端中读取用户的输入,将每一行视为一个命令。这些命令实际上是一组我已经编写的 shell 脚本,旨在支持照片工作流程。在这种解释环境中应该可以使用相同的编辑和调用功能。
在此脚本中具有 bash 命令历史记录和命令编辑功能将是非常可取的。
我想要一个 bash 脚本来实现 bash 命令行本身的一些功能:即命令历史记录和 vi 风格的命令编辑。
该脚本将永远循环(直到 crtl/d)并在终端中读取用户的输入,将每一行视为一个命令。这些命令实际上是一组我已经编写的 shell 脚本,旨在支持照片工作流程。在这种解释环境中应该可以使用相同的编辑和调用功能。
在此脚本中具有 bash 命令历史记录和命令编辑功能将是非常可取的。
也在寻找一种在脚本中模拟命令历史的方法,在网上找不到太多关于它的内容,所以我自己构建了一个简单的。不完全符合您的要求,但可能会给您或其他任何人一些参考。
它实际上只是一个大函数,除了处理类似提示的行为并从按 Enter 键返回屏幕上的字符串外,什么都不做。它允许浏览指定的历史文件,同时保存新的输入,返回。下面没有实现自动缩进或移动标记。我认为该脚本需要带有算术外壳的 bash 版本 4,但更改为较旧的语法并且 bash 3 应该可以工作。它还没有完全测试。
将其用作:
./scriptname.sh /optional/path/to/history_file
剧本
#!/bin/bash
# vim: ts=4:
function getInput() {
local hist_file="${1:-.script_hist}";
local result="";
local escape_char=$(printf "\u1b")
local tab=$(echo -e "\t");
local backspace=$(cat << eof
0000000 005177
0000002
eof
);
local curr_hist=0;
local curr_cmd="";
function browseHistory() {
! test -s "$hist_file" && return 1;
local max_hist="$(cat "$hist_file" | wc -l || echo 0)";
curr_hist=$((curr_hist + "$1"));
(( curr_hist > max_hist )) && curr_hist=$max_hist;
if (( curr_hist <= 0 )); then
curr_hist=0;
return 1;
fi
result="$(sed -n "$((max_hist - curr_hist + 1))p" < "$hist_file")";
return 0;
}
ifs=$IFS;
while true; do
# empty IFS, read one char
IFS= read -rsn1 input
if [[ $input == $escape_char ]]; then
# read two more chars, this is for non alphanumeric input
read -rsn2 input
fi
# check special case for backspace or tab first
# then move onto arrow keys or anything else in case
if [[ $(echo "$input" | od) = "$backspace" ]]; then
# delete last character of current on screen string
result=${result%?};
elif [ "$input" = "$tab" ]; then
# replace with function call for autofill or something
# it's unused but added in case it would be useful later on
continue;
else
case $input in
'[A')
! browseHistory '1' && result=$curr_cmd;
;;
'[B')
! browseHistory '-1' && result=$curr_cmd;
;;
'[D') continue ;; # left, does nothing right now
'[C') continue ;; # right, this is still left to do
*)
# matches enter and returns on screen string
[[ "$input" == "" ]] && break;
result+=$input
;;
esac
fi
# store current command, for going back after browsing history
(( curr_hist == 0 )) && curr_cmd="$result";
echo -en "\r\033[K";
echo -en "${result}"
done
IFS=$ifs;
test -n "$result" && echo "$result" >> "$hist_file";
return 0;
}
getInput $1