Как распечатать текст в терминале, как будто он вводится?

У меня есть простое 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

Это печатает сообщение к терминалу, но я хочу его, смотрят, как будто он вводится с последовательной задержкой между символами.

27
задан 1 May 2018 в 12:22

8 ответов

Это не работает с Уэйлендом; если Вы используете Ubuntu 17.10 и не изменились на использование Xorg при входе в систему, это решение не для Вас.

Можно использовать xdotool Install 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 цикл проходит каждую букву строки, сохраненной в переменной text, печать также key <letter> или key space в случае пространства, сопровождаемого sleep 0. и случайное число между 1 и 3 (xdotool sleep интерпретирует число как секунды). Целый вывод цикла затем передается по каналу к xdotool, который печатает буквы со случайной промежуточной задержкой. Если Вы хотите измениться, задержка просто изменяются (RANDOM%x)+y часть, y будучи ниже и x-1+y верхний предел – для 0,2 к 0,5 секундам это было бы (RANDOM%4)+2.

Обратите внимание, что этот подход не печатает текст, а скорее вводит его точно как пользователь, сделал бы, синтезировав единственные нажатия клавиш. В последствии текст вводится в в настоящее время фокусируемое окно; если Вы изменитесь, то часть фокуса текста будет введена в недавно сфокусированном окне, которое может или не может быть тем, что Вы хотите. В любом случае взглянули на другие ответы здесь, все из которых являются блестящими!

28
ответ дан 23 November 2019 в 00:59

Я попробовал xdotool после чтения ответа @dessert, но не мог заставить это работать по некоторым причинам. Таким образом, я придумал это:

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
24
ответ дан 23 November 2019 в 00:59

Вы упоминаете последовательную задержку между символами, но если Вы действительно захотите, чтобы она была похожа на то, что это было введенным, то синхронизация не будет совершенно последовательна. Для достижения этого, можно записать собственный ввод с 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 наполните также, Вы могли бы хотеть сделать a script запись для каждой из Ваших строк, и воспроизводит их, чередованный с tput/reset команды.

18
ответ дан 23 November 2019 в 00:59

Другая возможность использует Демонстрационное Волшебство, или, чтобы быть более точной просто функция печати этого набора сценария, который в основном составляет

#!/bin/bash

. ./demo-magic.sh -w2

p "this will look as if typed"

Под капотом это использует объем плазмы, который, конечно, можно также использовать для прямого получения желаемого эффекта, взгляды канонической формы следующим образом:

echo "this will look as if typed" | pv -qL 20
11
ответ дан 23 November 2019 в 00:59

В соответствии с моим псевдонимом я могу предложить другое решение:

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} отключает вывод, буферизующий, таким образом, каждый символ является распечатанным immediatly.
  • 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
ответ дан 23 November 2019 в 00:59

Другой инструмент, который мог бы работать, который не зависит от x11 или что бы то ни было, является asciicinema. Это записывает все, что Вы делаете в своем терминале, и позволяет Вам воспроизвести это, как будто это был снимок экрана, только затем это - просто базирующийся ASCII! Вам, возможно, придется временно отключить Вашу подсказку однако, чтобы это было просто визуально чисто. Как другой указали, добавив, что последовательная задержка не будет выглядеть естественной, и ввод ее самостоятельно мог бы быть одним из наиболее естественного вида, которого можно достигнуть.

Записав текст, можно сделать что-то как:

$ asciinema play [your recording].cast; cmatrix
6
ответ дан 23 November 2019 в 00:59

Я удивлен, что никто еще не упомянул это, но можно выполнить это с инструментами запаса и циклом:

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

Это просто циклы по вводимому символу символом и распечатывает их с задержкой после каждого. Единственный хитрый бит - то, что необходимо установить IFS на пустую строку, таким образом, удар не пытается отколоться пробелы.

Это решение очень просто, настолько добавляющие переменные задержки между символами, опечатками, независимо от того, что супер легко.

РЕДАКТИРОВАНИЕ (спасибо, @dessert): Если Вы хотите немного более естественный интерфейс, Вы могли бы вместо этого сделать

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

Это позволило бы Вам вызывать функцию как typeit foo bar вместо typeit 'foo bar'. Знайте, что без кавычек, аргументы подвергаются разделению слова удара, так например, typeit foo<space><space>bar распечатает foo<space>bar. Для сохранения пробела используйте кавычки.

6
ответ дан 23 November 2019 в 00:59

Во-первых, "смотрят, как будто это вводится, с последовательной задержкой между символами..." немного противоречащего другому положения, как указали другие. Что-то вводимое не имеет последовательной задержки. Когда Вы будете видеть что-то произведенное с непоследовательной задержкой, Вы получите холода. "Что взято по моему компьютеру!!!??!?"

Так или иначе...

Я должен разобрать крик к 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
ответ дан 23 November 2019 в 00:59

Другие вопросы по тегам:

Похожие вопросы: