BashがEOFを待たないようにする方法は?

BashがEOFを待たないようにする方法は?

そこで、キーボードLED(numlockとcapslock)を使用してデータを転送できるシンプルなBashスクリプトを作成しました(LTTの「Do Not Plug This USB In! – Hak5 Rubber Ducky」ビデオからインスピレーションを得ました)。これは私のスクリプトです。

#!/bin/bash
for i in `cat /dev/stdin | perl -lpe '$_=unpack"B*"' | sed 's/./\ &/g'`
 do export E=`expr $E + 1`
 echo "Bit number $E has a value of $i"
 if (( $i == 0 ))
  then
  xdotool key Caps_Lock
  sleep 0.1
  xdotool key Caps_Lock
 else
  xdotool key Num_Lock
  sleep 0.1
  xdotool key Num_Lock
fi
done

他の点は、キーボードのLEDが共通の高さではなく共通の低さであることです(これは、Linusのビデオと比較してLEDが長時間消えていることを意味します)。しかし、欠陥があります。 stdinでEOFが出るのを待ちますが、これは私が望むものではありません。私はそれがstdinに書き込まれたときにデータを読み取るミニモデムのように動作したいです(まあ、少なくとも改行文字の後)。次のことなくこれを行う方法はありますか?

  1. プログラミング言語を変更して
  2. スクリプト全体を壊さないで?

よろしくお願いします。

ベストアンサー1

これを行う方法はいくつかあります。すでにPerlでタスクの一部を実行しているので、最も簡単な方法は、おそらく次のようにPerlですべてのタスクを実行することです。用語::読み取りキー基準寸法。たとえば、

#!/usr/bin/perl -l

use Term::ReadKey;

# trap INT so we can reset the terminal on ^C
$SIG{INT} = sub { exit };

ReadMode 3;

while ($_ = ReadKey 0) {

  last if m/\cD/;

  @bits = split //, unpack "B*";

  for my $i (0..$#bits) {
    print "Bit number $i has a value of $bits[$i]";
    if ($bits[$i] == 0) {
      system("xdotool key Caps_Lock; sleep 0.1; xdotool key Caps_Lock");
    } else {
      system("xdotool key Num_Lock; sleep 0.1; xdotool key Num_Lock");
    };
  };
};

END {
  ReadMode 0;
};

または、CPANからモジュールをインストールしたくない場合は、で説明されてsttyいるperldoc -f getc方法を使用してgetc一度に1文字ずつ読み取ることができます。またはsetattr()stty

ただし、bash(およびcat&perl&sed)でこれを行うには、次のことに基づいて何かを試してみてください。

  1. catまず、stdinですでに読み取ることができるプログラム(Perlやsedや他のほとんどすべての操作が実行できる)にデータをパイプする必要がないことを認識してください。

  2. その後、Perlの出力をsedにパイプするたびに、おそらく何か間違ったことをしている可能性が高く、sedで行ったすべてのことをPerlスクリプトで実行できることに気づきました。 Perl には sed と同様に as/// 演算子もあります。

  3. mapfilebashに配列があることを覚えておいてください。 bash 組み込み関数を使用して、プログラムの出力を配列として読み取ることができます。プロセスの交換

そして

  1. bashは一度に1文字ずつ読み取るために使用できますread -n 1
#!/bin/bash
while read -n 1 char ; do

  case "$char" in
    $'\004') break ;; # Ctrl-D
  esac

  # This uses perl to print each bit separated by a newline. we could do it with s/// in perl,
  # but here i'm using split and join. the output from perl is read into bash array $bits.
  mapfile -t bits < <(printf '%s' "$char" | perl -lne 'print join("\n", split //, unpack"B*")')

  # that expr stuff is incredibly ugly. and decades obsolete for shell arithmetic.
  # i'm going to use let instead because I also find (( i=i+1 )) to be incredibly ugly. 
  count=0
  for i in "${bits[@]}" ; do
    let count+=1
    echo "Bit number $count has a value of $i"
    if [ "$i" -eq 0 ] ; then
      xdotool key Caps_Lock
      sleep 0.1
      xdotool key Caps_Lock
    else
      xdotool key Num_Lock
      sleep 0.1
      xdotool key Num_Lock
    fi
  done
done

おすすめ記事