Как включить клавиши со стрелками вверх/вниз для отображения предыдущих входов при использовании `read`?
Я жду ввода пользователя (используя 'read') в бесконечном цикле и хотел бы иметь историю команд, которая может показывать предыдущие входы, которые уже были введены, используя клавиши со стрелками вверх и вниз получения ^ [[A и ^ [[B. Возможно ли это?
Спасибо @l0b0 за ваш ответ. Это привело меня в правильном направлении. Поиграв с ним в течение некоторого времени, я понял, что мне также нужны следующие две функции, но мне еще не удалось их получить:
-
Если я нажму и добавлю что-то к предыдущей команде, я бы хотел, чтобы все это было сохранено в истории, а не просто добавление. Пример
$./up_and_down
Введите команду: hello
ENTER
Введите команду:
Up
Введите команду: привет, вы
ENTER
Введите команду:
Up
Введите команду: вы
(вместо "привет, ты" )
-
Если я не могу продолжать расти, потому что я в конце массива истории, я не хочу, чтобы курсор переместился в предыдущую строку, вместо этого я хочу, чтобы он оставался фиксированным.
Это то, что я до сих пор (up_and_down):
#!/usr/bin/env bash
set -o nounset -o errexit -o pipefail
read_history() {
local char
local string
local esc=$'\e'
local up=$'\e[A'
local down=$'\e[B'
local clear_line=$'\r\e[K'
local history=()
local -i history_index=0
# Read one character at a time
while IFS="" read -p "Enter command:" -n1 -s char ; do
if [[ "$char" == "$esc" ]]; then
# Get the rest of the escape sequence (3 characters total)
while read -n2 -s rest ; do
char+="$rest"
break
done
fi
if [[ "$char" == "$up" && $history_index > 0 ]] ; then
history_index+=-1
echo -ne $clear_line${history[$history_index]}
elif [[ "$char" == "$down" && $history_index < $((${#history[@]} - 1)) ]] ; then
history_index+=1
echo -ne $clear_line${history[$history_index]}
elif [[ -z "$char" ]]; then # user pressed ENTER
echo
history+=( "$string" )
string=
history_index=${#history[@]}
else
echo -n "$char"
string+="$char"
fi
done
}
read_history
Ответы
Ответ 1
Два решения, использующие параметр -e
для команды read
в сочетании со встроенной командой history
:
# version 1
while IFS="" read -r -e -d $'\n' -p 'input> ' line; do
echo "$line"
history -s "$line"
done
# version 2
while IFS="" read -r -e -d $'\n' -p 'input> ' line; do
echo "$line"
echo "$line" >> ~/.bash_history
history -n
done
Ответ 2
Я использую rlwrap, чтобы включить функцию readline в программе, которая ее не поддерживает. Может быть, вы могли бы попробовать это. Подставка rlwrap для оболочки readline. Эта команда перехватывает ваш ключ вверх и вниз и заменяет подсказку с предыдущими командами.
Синтакс просто rlwrap ./your-script
.
Ответ 3
Используйте параметр -e
для команды чтения (и убедитесь, что readline
настроен на использование клавиш со стрелками вверх/вниз для прокрутки истории команд).
help read | less -p '-e'
Ответ 4
Интересный вопрос - вот результат:
#!/usr/bin/env bash
set -o errexit -o nounset -o pipefail
read_history() {
local char=
local string=
local -a history=( )
local -i histindex=0
# Read one character at a time
while IFS= read -r -n 1 -s char
do
if [ "$char" == $'\x1b' ] # \x1b is the start of an escape sequence
then
# Get the rest of the escape sequence (3 characters total)
while IFS= read -r -n 2 -s rest
do
char+="$rest"
break
done
fi
if [ "$char" == $'\x1b[A' ]
then
# Up
if [ $histindex -gt 0 ]
then
histindex+=-1
echo -ne "\r\033[K${history[$histindex]}"
fi
elif [ "$char" == $'\x1b[B' ]
then
# Down
if [ $histindex -lt $((${#history[@]} - 1)) ]
then
histindex+=1
echo -ne "\r\033[K${history[$histindex]}"
fi
elif [ -z "$char" ]
then
# Newline
echo
history+=( "$string" )
string=
histindex=${#history[@]}
else
echo -n "$char"
string+="$char"
fi
done
}
read_history
Ответ 5
Насколько я знаю, нет. "вверх" и "вниз" являются столь же хорошими символами, как и любые (в этом случае Cp и Cn выполняют те же функции, что и "вверх" и "вниз" в bash), и могут быть введены как часть того, что вы пытаетесь прочитать.
То есть, предполагая, что вы имеете в виду bash встроенный read
. Вы можете проверить man-страницу для каких-либо параметров, но я не могу придумать какой-либо взлом, который сделает то, что вы хотите, по крайней мере, сейчас...
РЕДАКТ: Похоже, достаточно интересно. @теперь работаем и не имеют bash или времени для него, но это можно сделать, установив -n 1
на read
, а затем проверить, просто ли вы прочитали "вверх" или "вниз" и используя history
для получения необходимой команды. Вам, вероятно, придется придумать локальный var для подсчета "вверх" и "вниз", затем получить соответствующую команду из history
с соответствующим смещением, вывести его на экран и, если следующий read
будет возвращаться с пустую строку, используйте найденную команду.
Как я уже сказал, не могу проверить этот atm и не знаю, будет ли это работать.