使用`read`时如何启用向上/向下箭头键以显示先前的输入?

时间:2011-07-22 10:36:25

标签: bash shell

我正在等待无限循环中的用户输入(使用'read')并希望拥有命令历史记录,即能够使用向上和向下箭头键显示已输入的先前输入获得^ [[A和^ [[B.这可能吗?


感谢@ l0b0的回答。它让我朝着正确的方向前进。玩了一段时间后,我意识到我还需要以下两个功能,但我还没有设法得到它们:

  • 如果我按下并向上一个命令添加内容,我希望将整个内容保存在历史记录中,而不仅仅是添加内容。实施例

    $ ./up_and_down
    输入命令:hello
    输入
    输入命令:
    向上
    输入命令:你好 输入
    输入命令:
    向上
    输入命令:你
    (而不是“你好”)

  • 如果我不能继续上去因为我在历史数组的末尾,我不希望光标移动到上一行,而是希望它保持固定。

这是我到目前为止(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

5 个答案:

答案 0 :(得分:17)

使用-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

答案 1 :(得分:2)

我使用rlwrap在不支持它的程序中启用readline功能。也许你可以试试这个。 rlwrap代表readline包装器。此命令拦截您的密钥并按下键并替换提示whit先前的命令。

sintax只是rlwrap ./your-script

答案 2 :(得分:2)

对读取命令使用-e选项(并确保readline配置为使用向上/向下箭头键循环执行命令历史记录。)

help read | less -p '-e'

答案 3 :(得分:2)

有趣的问题 - 这是迄今为止的结果:

#!/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

答案 4 :(得分:0)

据我所知,没有。 “up”和“down”都是和任何一个一样好的符号(就此而言,Cp和Cn在bash中的功能上与“up”和“down”相同),并且可以作为你的''的一部分输入重新尝试阅读。

也就是说,假设你的意思是bash内置read。您可以查看联机帮助页以获取任何选项,但我想不出任何可以做您想做的黑客攻击,至少现在不行......

编辑:看起来很有趣。 @ work now&amp;没有bash或时间,但可以通过在-n 1上设置read,然后检查您是否只是阅读“向上”或“向下”并使用{{1}来完成获取所需的命令。您可能需要创建一个局部变量来计算“向上”和“向下”,然后从history获取具有适当偏移量的相关命令,将其输出到屏幕&amp;如果下一个history返回一个空字符串,请使用找到的命令。

正如我所说,不能测试这个atm,也不知道它是否会起作用。