cabeça, cauda e linha? [duplicado]

10

Qual é a maneira mais simples de extrair de um arquivo uma linha dada pelo seu número. Por exemplo, quero a 666ª linha de somefile . Como você faria isso no seu terminal ou em um shell script?

Eu posso ver soluções como head -n 666 somefile | tail -n 1 , ou mesmo a metade incorreta cat -n somefile | grep -F 666 , mas deve haver algo mais agradável, mais rápido e mais robusto. Talvez usando um comando / utilitário unix mais obscuro?

    
por phs 09.09.2015 / 14:41

5 respostas

23

sed ( s tream ed itor) é a ferramenta certa para esse tipo de trabalho:

sed -n '666p' somefile

Edit: @ solução tachomi sed '666q;d' somefile é melhor quando operando em um arquivo de texto enorme, porque faz sed sair depois de imprimir o padrão sem ler o resto do arquivo. Em todos os outros arquivos, a diferença é irrelevante.

    
por 09.09.2015 / 14:43
19

Você pode usar sed

sed -n '666p' somefile

Ou

sed '666!d' somefile

Ou em arquivos grandes

sed '666q;d' somefile 

No script bash

#!/usr/bin/bash
line=666
sed "$line"'q;d' somefile
    
por 09.09.2015 / 14:45
7

POSIXly (e talvez o mais rápido com um arquivo enorme):

tail -n +666 | head -n1
    
por 09.09.2015 / 14:46
6

tente

awk 'NR == 666 { print ; exit ; } '

ou

awk -vline=$LINE 'NR == line { print ;  exit ; } ' 
awk 'NR == '$LINE' { print ; exit ;  } '

se você quiser fornecer um número de linha por meio de uma variável shell ($ LINE).

e [dx] it: como por sugestão de terdon.

    
por 09.09.2015 / 14:52
2

Um caminho Perl:

perl -ne 'print && exit if $.==666' file

Eu testei criando um arquivo com os números de 1 a 999999. Nesse arquivo, a solução Perl acima e awk com exit são os mais rápidos dos mencionados até agora:

$ perl -le 'print for 1..999999' > file

$ time perl -ne 'print && exit if $.==666' file
666

real    0m0.004s
user    0m0.000s
sys     0m0.000s

$ time awk 'NR==666 { print ; exit ; } ' file
666

real    0m0.004s
user    0m0.000s
sys     0m0.000s

$ time tail -n +666 file | head -n1
666

real    0m0.021s
user    0m0.004s
sys     0m0.000s

$ time sed -n '666p' file
666

real    0m0.125s
user    0m0.112s
sys     0m0.012s

$ time awk 'NR==666' file
666

real    0m0.161s
user    0m0.156s
sys     0m0.000s

Dito isto, a sua solução original de head -n666 file | tail -n1 é também incrivelmente rápida, muito robusta e completamente portátil. Por que você acha que não é?

    
por 09.09.2015 / 16:24