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한 번에 한 문자씩 읽을 수 있습니다. 또는 .setattr()stty

그러나 bash(및 cat & perl & sed)에서 이 작업을 수행하려면 다음을 기반으로 뭔가를 시도해 볼 수 있습니다.

  1. cat첫째, stdin에서 이미 읽을 수 있는 프로그램(예: Perl 및 sed 및 기타 거의 모든 작업이 수행할 수 있음)에 데이터를 파이프 할 필요가 없다는 점을 인식하십시오 .

  2. 그런 다음 Perl의 출력을 sed로 파이프할 때마다 아마도 뭔가 잘못된 일을 하고 있을 가능성이 높으며 sed에서 수행한 모든 작업을 Perl 스크립트에서 수행할 수 있다는 것을 깨달았습니다. Perl에는 sed와 마찬가지로 as/// 연산자도 있습니다.

  3. mapfilebash에는 배열이 있다는 것을 기억하십시오. bash 내장 함수를 사용하여 프로그램의 출력을 배열로 읽을 수 있습니다.프로세스 교체.

그리고

  1. bash는 한 번에 한 문자씩 읽는 데 사용할 수 있습니다 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

관련 정보