入力されているかのように端末でテキストを印刷する方法は?


27

私は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

これにより、端末にメッセージが出力されますが、文字間で一貫した遅延が発生しているように見えます。


1
現実的であるためには、修正するために1つ以上のバックスペースを使用してランダムなタイプミスをスローする必要があると思います。たとえば、このコメントを入力しているときに、「スルー」にスペースを戻して「スロー」に修正する必要がありました。答えるのがより難しい質問になりますが、より現実的になります。キャラクターが30 CPSまたは60 CPSの一定のペースで繰り返される場合、人間らしく見えません。特定のキーは一緒に速く入力されますが、他のキーの組み合わせは遅く表示されます。キーの組み合わせを高速化するための何らかのパターンマッチングが必要です。
WinEunuuchs2Unix

2
@ WinEunuuchs2UnixこれはまだSimplySimplifiedだとは思わない。;)
デザート

回答:


28

これは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ループは、変数に保存された文字列のすべての単一の文字を経由text印刷のいずれかkey <letter>、またはkey space続く空間の場合にはsleep 0.1と3の間の乱数(xdotoolsleep解釈秒などの数)。次に、ループの出力全体がにパイプされxdotool、ランダムな遅延を挟んで文字が出力されます。遅延を変更したい場合は、下限と上限である部品を変更するだけです。0.2〜0.5秒間はになります。(RANDOM%x)+yyx-1+y(RANDOM%4)+2

このアプローチはしないことに注意してください印刷するテキストを、ではなく、入力し、単一のキーの押下を合成し、それが正確にユーザーが行うのと同じよう。結果として、テキストは現在フォーカスされているウィンドウに入力されます。テキストのフォーカス部分を変更すると、新しくフォーカスされたウィンドウにテキストが入力されますが、これは必要な場合とそうでない場合があります。いずれの場合も、ここで他の回答をご覧ください。それらはすべて素晴らしいです!


24

@dessertの回答を読んだ後、xdotoolを試しましたが、何らかの理由で動作しませんでした。だから私はこれを思いついた:

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

テキストを上記のコードにパイプすると、入力したとおりに印刷されます。また置き換えることにより、ランダム性を追加することができますsleep 0.1sleep 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

代わりにこれを行うと思います:(必要に応じて、改行と適切なインデントにwhile IFS= read -r line; do for (( i = 0; i < ${#line}; i++ )); do sleep 0.1; printf "%s" "${line:i:1}"; done; echo; done置き換え;ます)。IFS= read -rそしてprintf "%s"空白や特殊文字は任意の異なる方法で処理されていないことを確認してください。また、grep各行で文字に分割する必要はありません- for行内の各文字をループするだけで十分です。
デジタル外傷

18

文字間の一貫した遅延に言及しますが、本当に入力されたように見せたい場合、タイミングは完全に一貫していません。これを実現するには、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コマンドでインターリーブして再生することをお勧めします。


11

別の可能性は、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

1
このpvの使い方は素晴らしいです。
セバスチャン・スターク

3
にパイプechoする必要はありません。シェルがヒアストリングをサポートしている場合pvにのみ使用しpv -qL20 <<< "Hello world"てください。
dr01

8

私のニックネームに沿って、別のソリューションを提供できます。

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

変に見えますよね?

  • -MTime::HiRes=usleep通常は整数秒のみを受け入れるため、モジュールusleepから関数(マイクロ秒スリープ)をインポートします。Time::HiRessleep
  • -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秒)の間スリープします。

好奇心から:rand()0から引数(例では100kから300k)または引数の(例では100k + 1から300k-1)を返しますか?
デザート

1
intervalの数値[0,200k)、つまり0を含むが200kを除く数値を返します。正確な動作は、ここで説明「戻りランダム分数のより大きいまたはEXPRの値未満0に等しい(EXPRは正でなければならない。)。」
PerlDuck

1
これは-aおよび-nなしでは機能しません
rrauenza

@rrauenza Perl 5.20以降はサポートしています。-F含意し-a-a含意し-nます。
PerlDuck

ああ、私は5.16を使用していました。これはCentOS7にあります。
ラウエンツァ

6

x11などに依存しない、動作する可能性のある別のツールはasciicinemaです。ターミナルで行うすべてを記録し、スクリーンキャプチャのように再生することができます。それは、純粋にアスキーベースです。ただし、純粋に視覚的にきれいにするために、プロンプトを一時的に無効にする必要がある場合があります。他の人が指摘したように、一貫した遅延を追加することは自然に見えません。自分で入力することは、達成できる最も自然な外観の1つかもしれません。

テキストを記録した後、次のようなことができます。

$ asciinema play [your recording].cast; cmatrix

6

誰もまだこれについて言及していないことに驚いていますが、ストックツールとループでこれを達成できます。

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

入力文字を文字ごとにループし、それぞれの後に遅延して出力します。唯一の注意点は、bashがスペースを分割しようとしないように、IFSを空の文字列に設定する必要があることです。

このソリューションは非常にシンプルなので、文字間での可変遅延、タイプミスなどを非常に簡単に追加できます。

編集(ありがとう、@ 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。空白を保持するには、引用符を使用します。


良い提案ですが、単語分割が適用されることに注意する必要があります。たとえば、typeit foo<space>barはになりますがfoo bartypeit foo<space><space>barなりfoo barます。引用する必要があります。@dessertは自由に編集を提案します。私は自分でそれを行うことができますが、私はあなたにそれを信用する機会を与えたいです。
whereswalden

+1について教えてくださいread -n1(btw。はread -k1zshにあります)
セバスチャンスターク

5

最初に、「文字が入力されているように見え、文字間で一貫した遅延があります...」は、他の人が指摘しているように、少し矛盾しています。入力されるものには一貫した遅延がありません。一貫性のない遅延で生成されたものを見ると、悪寒を覚えます。「何が私のコンピューターに乗っ取られたのですか!!! ??!?」

とにかく...

expectほとんどのLinuxディストリビューションで利用できるはずのを叫ぶ必要があります。オールドスクール、私は知っていますが、インストールされていると仮定すると、それは簡単ではありません:

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

manページから:

-hフラグは、実際に入力する人間のように(ある程度)出力を送信します。キャラクター間に人間のような遅延が現れます。(アルゴリズムは、この特定のアプリケーションに合わせて修正されたワイブル分布に基づいています。)この出力は、変数「send_human」の値によって制御されます...

https://www.tcl.tk/man/expect5.31/expect.1.htmlを参照してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.