Como posso obter uma linha específica de um arquivo? [duplicado]

9

Eu quero extrair uma linha exata de um arquivo muito grande. Por exemplo, a linha 8000 seria obtida assim:

command -line 8000 > output_line_8000.txt
    
por Emilio Nicolás 17.05.2014 / 10:23

6 respostas

13

Já existe uma resposta com perl e awk . Aqui está uma resposta sed :

sed -n '8000{p;q}' file

A vantagem do comando q é que sed será encerrado assim que a linha 8000-th for lida ( diferente dos outros métodos perl e awk (era mudou depois de criatividade comum, haha)).

Uma possibilidade pura de bash (bash≥4):

mapfile -s 7999 -n 1 ary < file
printf '%s' "${ary[0]}"

Isso irá sugar o conteúdo de file em uma matriz ary (uma linha por campo), mas pule as primeiras 7999 linhas ( -s 7999 ) e só leia uma linha ( -n 1 ).

    
por 17.05.2014 / 10:33
9

É sábado e eu não tinha nada melhor para fazer, então testei alguns deles para velocidade. Acontece que as abordagens sed , gawk e perl são basicamente equivalentes. A cabeça e cauda é a mais lenta mas, surpreendentemente, a mais rápida por uma ordem de grandeza é a pura bash:

Aqui estão meus testes:

$ for i in {1..5000000}; do echo "This is line $i" >>file; done

O acima cria um arquivo com 50 milhões de linhas que ocupa 100M.

$ for cmd in "sed -n '8000{p;q}' file" \
            "perl -ne 'print && exit if $. == 8000' file" \
            "awk 'FNR==8000 {print;exit}' file" 
            "head -n 8000 file | tail -n 1" \
            "mapfile -s 7999 -n 1 ary < file; printf '%s' \"${ary[0]}\"" \
            "tail -n 8001 file | head -n 1"; do 
    echo "$cmd"; for i in {1..100}; do
     (time eval "$cmd") 2>&1 | grep -oP 'real.*?m\K[\d\.]+'; done | 
        awk '{k+=$1}END{print k/100}'; 
    done
sed -n '8000{p;q}' file
0.04502
perl -ne 'print && exit if $. == 8000' file
0.04698
awk 'FNR==8000 {print;exit}' file
0.04647
head -n 8000 file | tail -n 1
0.06842
mapfile -s 7999 -n 1 ary < file; printf '%s' "This is line 8000
"
0.00137
tail -n 8001 file | head -n 1
0.0033
    
por 17.05.2014 / 16:15
6

Você pode fazer isso de várias formas.

Usando perl :

perl -nle 'print && exit if $. == 8000' file

Usando awk :

awk 'FNR==8000 {print;exit}' file

Ou você pode usar tail e head para impedir a leitura de todo o arquivo até a linha 8000:

tail -n +8000 | head -n 1
    
por 17.05.2014 / 10:27
4

Outra versão com tail e head

head -n 8000 file | tail -n 1
    
por 17.05.2014 / 10:35
3

Você pode usar sed :

sed -n '8000p;' filename

Se o arquivo for grande, seria melhor sair:

sed -n '8000p;8001q' filename

Você também pode deixar de ler o arquivo inteiro usando awk ou perl também:

awk 'NR==8000{print;exit}' filename
perl -ne 'print if $.==8000; last if $.==8000' filename
    
por 17.05.2014 / 10:35
-1

Que tal isso?

$ cat -n filename | grep -E "[ \t]+8000"

Exemplo

$ cat -n /etc/abrt/plugins/CCpp.conf  | grep -E "^[ \t]+16"
    16  #DebuginfoLocation = /var/cache/abrt-di
    
por 18.05.2014 / 15:29