AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / ubuntu / 问题 / 1030099
Accepted
SimplySimplified
SimplySimplified
Asked: 2018-05-01 04:37:45 +0800 CST2018-05-01 04:37:45 +0800 CST 2018-05-01 04:37:45 +0800 CST

如何在终端中打印文本,就好像它正在输入一样?

  • 772

我有一个简单的echo打印输出,已添加到我的.bashrc:

echo "$(tput setaf 2)Wake up....."
sleep 2s
reset
sleep 2s
echo "$(tput setaf 2)Wake up....."
sleep 2s
reset
echo "$(tput setaf 2)Wake up neo....."
sleep 2s
echo "$(tput setaf 2)The Matrix has you......"
sleep 2s
reset
echo "$(tput setaf 2)Follow the white rabbit......"
sleep 2s
reset
cmatrix

这会向终端打印一条消息,但我希望它看起来好像正在输入,字符之间有一致的延迟。

command-line bash echo
  • 8 8 个回答
  • 52378 Views

8 个回答

  • Voted
  1. Best Answer
    dessert
    2018-05-01T04:45:03+08:002018-05-01T04:45:03+08:00

    这不适用于 Wayland;如果您使用的是 Ubuntu 17.10 并且没有更改为在登录时使用 Xorg,则此解决方案不适合您。

    你可以使用xdotool 安装 xdotool它。如果击键之间的延迟应该是一致的,就这么简单:

    xdotool type --delay 100 something
    

    这种类型在每次击键之间有毫秒something的延迟。100


    如果击键之间的延迟应该是随机的,比如说从 100 到 300 毫秒,事情会变得有点复杂:

    $ text="some text"
      for ((i=0;i<${#text};i++));
      do
        if [[ "${text:i:1}" == " " ]];
        then
          echo -n "key space";
        else
          echo -n "key ${text:i:1}";
        fi;
      [[ $i < $((${#text}-1)) ]] && echo -n " sleep 0.$(((RANDOM%3)+1)) ";
      done | xdotool -
    

    这个for循环遍历保存在 variable 中的字符串的每个字母text,打印key <letter>或者key space在空格后跟sleep 0.一个 1 到 3 之间的随机数的情况下打印(xdotool'ssleep将数字解释为秒)。然后将循环的整个输出通过管道传输到xdotool,它打印具有随机延迟的字母。如果您想更改延迟,只需更改部分,即下限和上限 - 0.2 到 0.5 秒。(RANDOM%x)+yyx-1+y(RANDOM%4)+2

    请注意,这种方法不会打印文本,而是像用户一样输入文本,合成单个按键。结果,文本被输入到当前聚焦的窗口中;如果您更改文本的焦点部分,则会在新聚​​焦的窗口中输入,这可能是也可能不是您想要的。无论哪种情况,请查看此处的其他答案,所有这些都很棒!

    • 28
  2. Sebastian Stark
    2018-05-01T06:53:45+08:002018-05-01T06:53:45+08:00

    我在阅读@dessert 的答案后尝试了 xdotool,但由于某种原因无法使其正常工作。所以我想出了这个:

    while read line
    do
        grep -o . <<<$line | while read a
        do
            sleep 0.1
            echo -n "${a:- }"
        done
        echo
    done
    

    将您的文本输入到上面的代码中,它将像打字一样打印。您还可以通过替换为来添加sleep 0.1随机性sleep 0.$((RANDOM%3))。

    带有假错字的扩展版

    这个版本会不时引入一个虚假的错字并更正它:

    while read line
    do
        # split single characters into lines
        grep -o . <<<$line | while read a
        do
            # short random delay between keystrokes
            sleep 0.$((RANDOM%3))
            # make fake typo every 30th keystroke
            if [[ $((RANDOM%30)) == 1 ]]
            then
                # print random character between a-z
                printf "\\$(printf %o "$((RANDOM%26+97))")"
                # wait a bit and delete it again
                sleep 0.5; echo -ne '\b'; sleep 0.2
            fi
            # output a space, or $a if it is not null
            echo -n "${a:- }"
        done
        echo
    done
    
    • 25
  3. Digital Trauma
    2018-05-01T09:45:08+08:002018-05-01T09:45:08+08:00

    您提到了字符之间的一致延迟,但如果您真的希望它看起来像正在输入,那么时间将不会完全一致。为此,您可以使用命令记录自己的输入并使用以下script命令进行回放scriptreplay:

    $ script -t -c "sed d" script.out 2> script.timing
    Script started, file is script.out
    Wake up ...
    Wake up ...
    Wake up Neo ...
    Script done, file is script.out
    $ 
    $ scriptreplay script.timing script.out
    Wake up ...
    Wake up ...
    Wake up Neo ...
    
    $ 
    

    按 CTRL-D 停止录制。

    -t将参数传递给script指示它还生成时间信息,我已将其重定向到script.timing文件。我已将sed d其作为命令传递给,script因为这只是一种吸收输入(并记录击键)而没有副作用的方法。

    如果你也想做所有tput/的reset事情,你可能想为你的script每一行做一个录音,然后回放它们,与tput/reset命令交错。

    • 18
  4. godfatherofpolka
    2018-05-01T11:51:44+08:002018-05-01T11:51:44+08:00

    另一种可能是使用Demo Magic,或者更准确地说只是这个脚本集合的打印功能,基本上相当于

    #!/bin/bash
    
    . ./demo-magic.sh -w2
    
    p "this will look as if typed"
    

    在后台,这使用了pv,当然你也可以直接使用它来获得想要的效果,基本形式如下所示:

    echo "this will look as if typed" | pv -qL 20
    
    • 11
  5. PerlDuck
    2018-05-01T09:20:06+08:002018-05-01T09:20:06+08:00

    根据我的昵称,我可以提供另一种解决方案:

    echo "something" | 
        perl \
            -MTime::HiRes=usleep \
            -F'' \
            -e 'BEGIN {$|=1} for (@F) { print; usleep(100_000+rand(200_000)) }'
    

    看起来很奇怪,不是吗?

    • -MTime::HiRes=usleep从模块导入函数usleep(微秒睡眠),Time::HiRes因为通常sleep只接受整数秒。
    • -F''将给定的输入拆分为字符(分隔符为空'')并将字符放入数组中@F。
    • BEGIN {$|=1}禁用输出缓冲,以便立即打印每个字符。
    • for (@F) { print; usleep(100_000+rand(200_000)) }只是迭代字符
    • 在数字中加下划线是在 Perl 中使用某种千位分隔符的常用方法。Perl 简单地忽略了它们,因此我们可以例如编写1_000(== 1000) 或者即使1_0_00我们认为这样更容易阅读。
    • rand()返回一个介于 0 和给定参数之间的随机数,因此它一起休眠 100,000 到 299,999 微秒(0.1-0.3 秒)。
    • 8
  6. whereswalden
    2018-05-01T18:04:26+08:002018-05-01T18:04:26+08:00

    我很惊讶还没有人提到这一点,但您可以使用库存工具和循环来完成此操作:

    typeit() {
        local IFS=''
        while read -n1 c; do
            echo -n "$c"
            sleep .1
        done <<< "$1"
    }
    

    它只是逐个字符地循环输入,并在每个字符之后延迟打印出来。唯一棘手的一点是您必须将 IFS 设置为空字符串,因此 bash 不会尝试分割您的空间。

    这个解决方案非常简单,所以在字符之间添加可变延迟,错别字,任何超级容易的东西。

    编辑(谢谢,@dessert):如果你想要一个更自然的界面,你可以改为

    typeit() {
        local IFS=''
        while read -n1 c; do
            echo -n "$c"
            sleep .1
        done <<< "$@"
    }
    

    这将允许您调用函数typeit foo bar而不是typeit 'foo bar'. 请注意,如果没有引号,参数会受到 bash 的分词,例如typeit foo<space><space>bar将 print foo<space>bar。要保留空格,请使用引号。

    • 6
  7. rien333
    2018-05-03T05:31:30+08:002018-05-03T05:31:30+08:00

    另一个可能有效的工具是asciicinema,它不依赖于 x11 或其他任何东西。它会记录您在终端中所做的一切,并让您像截屏一样重播它,只有这样它才纯粹基于 ascii!但是,您可能必须暂时禁用您的提示,以使其在视觉上完全干净。正如其他人指出的那样,添加一致的延迟看起来并不自然,而自己输入可能是您可以获得的最自然的外观之一。

    录制文本后,您可以执行以下操作:

    $ asciinema play [your recording].cast; cmatrix
    
    • 6
  8. Mike S
    2018-05-03T04:53:32+08:002018-05-03T04:53:32+08:00

    首先,正如其他人所指出的那样,“看起来好像正在输入,字符之间有一致的延迟......”有点矛盾。输入的内容没有一致的延迟。当您看到某些产品的延迟不一致时,您会感到不寒而栗。“什么占用了我的电脑!!!???”

    反正...

    我必须大声疾呼expect,它应该在大多数 Linux 发行版上都可用。老派,我知道,但是——假设它已经安装——它再简单不过了:

    echo 'set send_human {.1 .3 1 .05 2}; send -h "The Matrix has you......\n"' | expect -f /dev/stdin
    

    从手册页:

    -h 标志强制(有点)像人类实际打字一样发送输出。人物之间出现类似人类的延迟。(该算法基于 Weibull 分布,并进行了修改以适应此特定应用程序。)此输出由变量“send_human”的值控制...

    见https://www.tcl.tk/man/expect5.31/expect.1.html

    • 5

相关问题

  • 如何从命令行仅安装安全更新?关于如何管理更新的一些提示

  • 如何从命令行刻录双层 dvd iso

  • 如何从命令行判断机器是否需要重新启动?

  • 文件权限如何工作?文件权限用户和组

  • 如何在 Vim 中启用全彩支持?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何运行 .sh 脚本?

    • 16 个回答
  • Marko Smith

    如何安装 .tar.gz(或 .tar.bz2)文件?

    • 14 个回答
  • Marko Smith

    如何列出所有已安装的软件包

    • 24 个回答
  • Marko Smith

    无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗?

    • 25 个回答
  • Martin Hope
    Flimm 如何在没有 sudo 的情况下使用 docker? 2014-06-07 00:17:43 +0800 CST
  • Martin Hope
    Ivan 如何列出所有已安装的软件包 2010-12-17 18:08:49 +0800 CST
  • Martin Hope
    La Ode Adam Saputra 无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗? 2010-11-30 18:12:48 +0800 CST
  • Martin Hope
    David Barry 如何从命令行确定目录(文件夹)的总大小? 2010-08-06 10:20:23 +0800 CST
  • Martin Hope
    jfoucher “以下软件包已被保留:”为什么以及如何解决? 2010-08-01 13:59:22 +0800 CST
  • Martin Hope
    David Ashford 如何删除 PPA? 2010-07-30 01:09:42 +0800 CST

热门标签

10.10 10.04 gnome networking server command-line package-management software-recommendation sound xorg

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve