Чтение фрагментов из канала и выполнение команды для каждого фрагмента

Я нашел решение, с помощью cut и a while- цикл

#!/bin/bash

RUNDIR=$1

n=2
TMPDIR=
while [ $(echo $RUNDIR | cut -d '/' -f$(printf $n)) ]; do
      TMPDIR=$TMPDIR'/'$(echo $RUNDIR | cut -d '/' -f$(printf $n))
      if [ -a $TMPDIR ]; then
         echo $TMPDIR' exists'
      else
         echo $TMPDIR' does not exist; creating directory...'
         mkdir $TMPDIR
      fi
      n=$(printf $(($n + 1)))
done

Существует ли более компактный способ сделать это?

3
07.10.2015, 19:27
2 ответа

Raw read не будет блокироваться, если труба не пуста - он вернет столько байт, сколько доступно в трубе, даже если вы запросите больше. Вы можете воспользоваться этим и запускать hexdump -C при каждом успешном возврате от read.

#define _BSD_SOURCE
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

#define N (8*512)  //pipe size on my system as shown in `ulimit -a`
static char buf[N];

int main(){
  ssize_t nread;
  FILE* p;

  for(;;){
    do { nread = read(0, buf, N); }while (nread < 0 && errno == EINTR);
    if(nread == 0) return 0;    //EOF
    if(nread < 0) goto error; 
    p = popen("hexdump -C", "w"); if(!p) goto error;
    if(fwrite(buf, sizeof(char), nread, p) != nread) goto error;
    pclose(p);
  }

  return 0;
  error:
    perror(""); return 1;
}

Вы можете сохранить это, например, как shovel.c, а затем make shovel (или gcc shovel.c -o shovel) и использовать его в своей трубе.

Или, если вас это не интересует, вот ruby сниппет, который должен делать то же самое:

tail -f file |
ruby -e 'PSIZE=8*512; 
      while(bytes = STDIN.readpartial(PSIZE));
          IO.popen("hexdump -C","w") {|p| p.syswrite(bytes) }
      end '
3
27.01.2020, 21:14

Если вы хотите получить что-то дешевое, что просто печатает шестнадцатеричные данные в том виде, в каком они появляются вы можете использовать этот perl скрипт:

perl -e '$| = 1; $i = 1;
while(1){
 sysread(STDIN,$ch,1) or exit;
 printf "%02x%s",ord($ch),$i++%16==0?"\n":" ";
}'

А если вы действительно хотите прочитать до блока и запустить hexdump:

perl -e '$| = 1; $i = 1; $rin = ""; vec($rin, fileno(STDIN), 1) = 1;
open(F,"|hexdump -C") or die;
while(1){
 $nfound = select($rout=$rin, undef, undef, 0);
 if($nfound==1){
  sysread(STDIN,$data,999) or exit;
  syswrite(F,$data) or die;
 }else{
  close(F);
  open(F,"|hexdump -C") or die;
  select($rout=$rin, undef, undef, undef);
 }
}'
3
27.01.2020, 21:14

Теги

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