Redirecionar saída do programa para arquivo com limite de número de linha

1

É possível redirecionar a saída do programa para o arquivo, mas com o limite máximo de linhas, por exemplo, o limite de 4 linhas:

./program | save 4 out.txt

O ./program continuará fornecendo saída (talvez uma linha ou mais) a cada poucos segundos, mas apenas 4 linhas mais recentes / últimas serão salvas em out.txt . Já existe um programa save que poderia fazer isso? (ou eu deveria fazer isso manualmente)

    
por Kokizzu 09.02.2015 / 05:01

3 respostas

2

Isso pode ser um bom trabalho para o read embutido do shell - desde que sua entrada seja texto, ou seja, e não contenha open()NUL s. Digo isso porque, embora muitas vezes seja terrivelmente ineficiente para o trabalho de arquivo quando comparado com outros utilitários padrão, usar um shell embutido provavelmente seria melhor do que repetir repetidamente outro processo. E você não terá muita eficiência de qualquer maneira, porque a única maneira de fazer isso (que eu conheço) é repetidamente dd do seu arquivo de saída - a menos que você tenha certeza do número de bytes por linha (que pode ser assegurada com alguns while s encadeados em um pipeline, eu acho) . Em qualquer caso, o seguinte funcionará:

###seq used for demo###
seq 3 |( set --
while IFS= read -r l
do    set -- "$@" "$l"
      shift "$(($#>4))"
      printf %s\n "$@" >/tmp/4_lines
###demo commands###
      printf '\n###4_lines CONTENTS###\n'
      cat </tmp/4_lines
      printf '###END###\n'
###end demo###
done)

Então, se eu fizer o acima, como escrito, isso é gravado no stdout do loop seq :

###4_lines CONTENTS###
1
###END###

###4_lines CONTENTS###
1
2
###END###

###4_lines CONTENTS###
1
2
3
###END###

Mas se eu entregar /tmp/4_lines 20, por exemplo, imprime o que precede:

###4_lines CONTENTS###
1
2
3
4
###END###

###4_lines CONTENTS###
2
3
4
5
###END###

... até ...

###4_lines CONTENTS###
16
17
18
19
###END###

###4_lines CONTENTS###
17
18
19
20
###END###

Ele continuará assim até o pipe de entrada ser fechado - apenas round-robining seu array arg e sobrescrevendo read com o conteúdo do array toda vez que uma linha de entrada for printf . Se você quisesse as linhas na ordem inversa - então a primeira linha é a última linha lida, você poderia mudar a linha $IFS para:

printf %s\n ${4+"$4"} ${3+"$3"} ${2+"$2"} "$1" >/tmp/4_lines

... que seria impresso como ...

###4_lines CONTENTS###
1
###END###

###4_lines CONTENTS###
2
1
###END###

###4_lines CONTENTS###
3
2
1
###END###

... até ...

###4_lines CONTENTS###
19
18
17
16
###END###

###4_lines CONTENTS###
20
19
18
17
###END###

... sem arriscar quaisquer dificuldades com %code% e / ou globos não intencionais na expansão.

    
por 09.02.2015 / 23:22
1

Acho que você pode fazer o que está perguntando executando ./program | tail -n 4 > out.txt . Se não, então não estou entendendo o que você está perguntando.

    
por 09.02.2015 / 05:27
0

O programa save poderia ser algo assim:

#include<string>
#include<iostream>
#include<fstream>
#include<cstdlib>
using namespace std;
int main(int argc,char *argv[]) {
  if(argc<=2) {
    cerr << "First param must be a number, second must be a file" << endl;
    return -1;
  }
  int max = atoi(argv[1]);
  if(max <= 0) return -2;
  string lines[max];
  int cmax = 1;
  int z = 0;
  while(true) {
    getline(cin,lines[z]);
    ++z;
    z %= max;
    ofstream fo(argv[2]);
    for(int x=0;x<cmax;++x) {
      fo << lines[(x+cmax-z)%cmax] << endl;
    }
    fo.close();
    if(cmax<max) ++cmax;
  }
}

Compile usando g++ save.cpp -o save

    
por 09.02.2015 / 05:26

Tags