如何让 Bash 不等待 EOF?

如何让 Bash 不等待 EOF?

因此,我制作了一个简单的 Bash 脚本,可以使用键盘 LED(numlock 和 capslock)来传输数据(受到 LTT 的“请勿插入此 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 关闭的时间更长)。然而,它有一个缺陷。它会等到来自标准输入的 EOF,这不是我想要的。我希望它像迷你调制解调器一样,在将数据写入标准输入时读取数据(嗯,至少在换行符之后)。有没有一种方法可以做到这一点而无需:

  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()POSIX 模块(包含在 perl 中)中的函数而不是运行stty.

但是,由于您想在 bash (以及 cat & perl & sed)中执行此操作,因此您可以尝试基于此的操作:

  1. 首先,认识到您永远不需要使用cat管道将数据传输到已经可以从 stdin 读取的程序中(就像 perl 和 sed 以及几乎所有其他东西都可以做的那样)。

  2. 然后意识到,每当您将 perl 的输出传输到 sed 时,您可能做错了,并且可以在 perl 脚本中执行您在 sed 中执行的任何操作。 Perl 也有 as/// 运算符,就像 sed 一样。

  3. mapfile请记住,bash 有数组,您可以使用 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

相关内容