簡體   English   中英

使用`read`時如何啟用向上/向下箭頭鍵以顯示以前的輸入?

[英]How to enable the up/down arrow keys to show previous inputs when using `read`?

我正在無限循環中等待用戶輸入(使用“讀取”),並希望擁有命令歷史記錄,即能夠使用向上和向下箭頭鍵顯示先前已輸入的輸入,而不是獲取 ^ [[A 和 ^[[B。 這可能嗎?


感謝@l0b0 的回答。 它讓我朝着正確的方向前進。 玩了一段時間后,我意識到我還需要以下兩個功能,但我還沒有設法獲得它們:

  • 如果我按下並在上一個命令中添加一些內容,我希望將整個內容保存在歷史記錄中,而不僅僅是添加內容。 例子

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

  • 如果因為我在歷史數組的末尾而無法繼續上升,我不希望 cursor 移動到上一行,而是希望它保持固定。

這是我到目前為止所擁有的(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

兩種使用read命令的-e選項結合內置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

有趣的問題 - 這是迄今為止的結果:

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

我使用rlwrap在不支持它的程序中啟用 readline 功能。 也許你可以試試這個。 rlwrap 代表 readline 包裝器。 此命令攔截您的按鍵向上和向下按鍵,並將提示符替換為先前的命令。

sintax 就是rlwrap./your-script

對 read 命令使用-e選項(並確保將readline配置為使用向上/向下箭頭鍵循環瀏覽命令歷史記錄)。

help read | less -p '-e'

據我所知,沒有。 "up" 和 "down" 和任何符號一樣好(就此而言,Cp 和 Cn 在 bash 中的功能與 "up" 和 "down" 相同),並且可以作為你的一部分輸入重新嘗試閱讀。

也就是說,假設您的意思是 bash 內置read 您可以查看手冊頁中的任何選項,但我想不出任何可以做您想做的事情的黑客,至少現在不是......

編輯:似乎很有趣。 @ work now & don't have bash 或時間,但可以通過在read上設置-n 1來完成,然后檢查您是否只是讀取“up”或“down”並使用history來獲取所需的命令. 您可能必須發明一個本地變量來計算“向上”和“向下”,然后從history中獲取具有適當偏移量的相關命令,output 將其顯示到屏幕&如果下一次read返回一個空字符串,使用找到的命令。

正如我所說,無法測試此自動取款機,也不知道它是否會起作用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM