Linux bash - 重新打印用户的输入

时间:2012-05-17 14:16:37

标签: linux bash

我有一个旧的shell脚本需要移动到bash。此脚本打印某些活动的进度并等待用户的命令。如果用户未执行任何操作15秒,则会重新绘制屏幕并显示新进度并再次启动计时器。这是我的问题:

我正在尝试使用read -t 15 myVar - 这样在15秒的等待循环后将重新启动。然而,有一个场景给我带来了一个问题:

  • 屏幕重绘和脚本等待输入(打印'Enter command:')
  • 用户输入foo但未按输入
  • 15秒后再次重绘屏幕并且脚本等待输入 - 请注意,foo未显示在屏幕上的任何位置(打印“Enter command:”)
  • 用户输入bar并按输入

此时变量$myVar包含“foobar”。

我需要什么?我正在寻找一种方法来查找用户输入的第一个字符串,因此我可以在刷新状态后重新显示它。这样用户会看到: Enter command: foo

在Solaris上,我可以使用stty -pendin将输入保存到某种缓冲区中,并在刷新后运行stty pendin以从缓冲区获取此输入并将其打印在屏幕上。

Linux是否等同于stty pendin功能?或许你知道我的问题的一些bash解决方案?

4 个答案:

答案 0 :(得分:2)

我想一种方法是手动累积用户输入...使用read-n1,以便它在每个字符后返回,然后你可以将它添加到你的字符串中。为防止过度绘制,您必须计算15秒钟内剩余秒数...


附录:

有关空格/返回的注释 - 您基本上想要使用没有所需字符的IFS,例如空格

示例:

XIFS="${IFS}"  # backup IFS
IFS=$'\r'      # use a character your user is not likely to enter (or just the same but w/o the space)


# Enter will look like en empty string
$ read -n1 X; echo --; echo -n "${X}" | od -tx1

--
0000000


# space will be presented as a character
$ read -n1 X; echo --; echo -n "${X}" | od -tx1
 --
0000000 20
0000001


# after you are all done, you probably wantto restore the IFS
IFS="${XIFS}"

答案 1 :(得分:1)

扩展@nhed所说的内容,或许是这样的:

#!/bin/bash

limit=5

draw_screen () {
    clear;
    echo "Elapsed time: $SECONDS" # simulate progress indicator
    printf 'Enter command: %s' "$1"
}

increment=$limit
str=
end=0
while ! [ $end -eq 1 ] ; do
    draw_screen "$str"
    while [ $SECONDS -lt $limit ] && [ $end -eq 0 ] ; do
            c=
            IFS= read -t $limit -r -n 1 -d '' c
            if [ "$c" = $'\n' ] ; then
                    end=1
            fi
            str="${str}${c}"
    done
    let limit+=increment
done
str="${str%$'\n'}" # strip trailing newline

echo "input was: '$str'"

解决方案并不理想:

  • 您有时可以在循环中间输入并弄乱输入
  • 你不能很好地编辑任何东西(但这可以通过更多的工作来修复)

但也许这对你来说已经足够了。

答案 2 :(得分:1)

如果你有Bash 4:

read -p 'Enter something here: ' -r -t 15 -e -i "$myVar" myVar

-e打开用户文本条目的readline支持。 -i使用以下文本作为它向用户显示的输入缓冲区的默认内容。在这种情况下,以下文本是您正在阅读的变量的先前内容。

演示:

$ myVar='this is some text'    # simulate previous entry
$ read -p 'Enter something here: ' -r -t 15 -e -i "$myVar" myVar
Enter something here: this is some text[]

[]表示光标。如果需要,用户将能够退格并更正以前的文本。

答案 3 :(得分:1)

好的,我想我有解决方案。我接受了nhed的命题,并对它进行了一些工作:)

主代码打印一些状态并等待输入:

while :
do
    # print the progress on the screen
    echo -n "Enter command: "
    tput sc # save the cursor position
    echo -n "$tmpBuffer" # this is buffer which holds typed text (no 'ENTER' key yet)
    waitForUserInput
    read arguments <<< $(echo $mainBuffer) # this buffer is set when user presses 'ENTER'
    mainBuffer="" # don't forget to clear it after reading
    # now do the action requested in $arguments
done

函数waitForUserInput等待10秒按键。如果没有输入 - 退出,但已输入的键保存在缓冲区中。如果按下了键,则会对其进行解析(添加到缓冲区,或者在退格时从缓冲区中删除)。输入缓冲区保存到另一个缓冲区,从中读取该缓冲区以进行进一步处理:

function waitForUserInput {
    saveIFS=$IFS # save current IFS
    IFS="" # change IFS to empty string, so 'ENTER' key can be read

    while :
    do
        read -t10 -n1 char
        if (( $? == 0 ))
        then
            # user pressed something, so parse it
            case $char in
                $'\b')
                    # remove last char from string with sed or perl
                    # move cursor to saved position with 'tput rc'
                    echo -n "$tmpBuffer"
                    ;;
                "")
                    # empty string is 'ENTER'
                    # so copy tmpBuffer to mainBuffer
                    # clear tmpBuffer and return to main loop
                    IFS=$saveIFS
                    return 0
                    ;;
                 *)
                    # any other char - add it to buffer
                    tmpBuffer=$tmpBuffer$char
                    ;;
            esac
        else
            # timeout occured, so return to main function
            IFS=$saveIFS
            return 1
        fi
    done
}

感谢各位的帮助!