Bash: filtra linhas por número de linha

4

Se eu tiver um arquivo delimitado com muitas linhas e colunas ( data.txt ):

346 dfd asw  34
565 sd  wdew 34
667 ffg wew  23
473 sa  as   21
533 jhf qwe  54

e outro arquivo com números de linha que eu quero extrair ( positions.txt )

3
5
8

Como eu uso o arquivo positions.txt para extrair essas posições de data.txt ? Este é o resultado que eu esperaria para este exemplo:

667 ffg wew  23
533 jhf qwe  54
    
por rmf 19.01.2018 / 18:00

5 respostas

5

Simplesmente com awk :

awk 'NR==FNR{ pos[$1]; next }FNR in pos' positions.txt data.txt
  • NR==FNR{ ... } - processando o primeiro arquivo de entrada (ou seja, positions.txt ):
    • pos[$1] - acumulando posições (números de registro) configurados como pos array keys
    • next - pula para o próximo registro
  • FNR in pos - durante o processamento do segundo arquivo de entrada data.txt ( FNR indica quantos registros foram lidos do arquivo de entrada atual). Imprimir registro somente se o número de registro atual FNR estiver na matriz de posições pos (pesquisa nas chaves)

Exemplo de saída:

667 ffg wew  23
533 jhf qwe  54
...
    
por 19.01.2018 / 18:05
5

Primeiro, crie um script sed do arquivo positions.txt :

sed 's/$/p/' positions.txt

Isto irá produzir

3p
5p
8p

Este script simples apenas imprimirá as linhas indicadas.

Em seguida, aplique isso ao arquivo data.txt . Se você estiver usando bash (ou qualquer shell que entenda substituições de processo com <( ... ) ):

sed -n -f <( sed 's/$/p/' positions.txt ) data.txt

O -n pára sed da saída de algo diferente do que é explicitamente impresso pelo script sed fornecido.

Com os exemplos dados, isso produzirá

667 ffg wew  23
533 jhf qwe  54

Se não estiver usando bash ,

sed 's/$/p/' positions.txt >filter.sed
sed -n -f filter.sed data.txt
rm -f filter.sed

... fará o mesmo.

    
por 19.01.2018 / 18:05
3

Se positions.txt estiver classificado, também é possível fazer isso em uma única passagem pelos dois arquivos e sem armazenar positions.txt completo. Basta ler a próxima linha do positions.txt quando a linha correspondente anterior for atendida:

$ awk -vpos=positions.txt 'function get() { getline num < pos } 
     BEGIN { get() } NR==num { print; get() }' data.txt                 
667 ffg wew  23
533 jhf qwe  54

Na prática, isso é útil apenas se os dois arquivos forem realmente grandes ou se você estiver realmente com pouca memória

.

    
por 19.01.2018 / 20:51
1
join <(cat -n data.txt) positions.txt | cut -d ' ' -f2-
    
por 19.01.2018 / 23:24
0

podemos fazer isso por simples loop

Method1 usando sed e loop

for i in 'cat positions.txt'; do sed -n ""$i"p" data.txt ; done

saída

667 ffg wew  23
533 jhf qwe  54

Method2 usando awk e loop

for i in 'cat positions.txt'; do awk -v i="$i" 'NR==i {print $0}' data.txt ;done

saída

667 ffg wew  23
533 jhf qwe  54
    
por 19.01.2018 / 18:42