Imprima linhas numeradas ímpares, imprima linhas numeradas pares


18

Quero imprimir as linhas de números ímpares e pares de arquivos.

Eu encontrei este script de shell que faz uso de eco.

#!/bin/bash
# Write a shell script that, given a file name as the argument will write
# the even numbered line to a file with name evenfile and odd numbered lines
# in a text file called oddfile.
# -------------------------------------------------------------------------
# Copyright (c) 2001 nixCraft project <http://cyberciti.biz/fb/>
# This script is licensed under GNU GPL version 2.0 or above
# -------------------------------------------------------------------------
# This script is part of nixCraft shell script collection (NSSC)
# Visit http://bash.cyberciti.biz/ for more information.
# -------------------------------------------------------------------------

file=$1
counter=0

eout="evenfile.$$" # even file name
oout="oddfile.$$" # odd file name

if [ $# -eq 0 ]
then
    echo "$(basename $0) file"
    exit 1
fi

if [ ! -f $file ]
then
    echo "$file not a file"
    exit 2
fi

while read line
do
    # find out odd or even line number
    isEvenNo=$( expr $counter % 2 )

    if [ $isEvenNo -ne 0 ]
    then
        # even match
        echo $line >> $eout
    else
        # odd match
        echo $line >> $oout
    fi
    # increase counter by 1
    (( counter ++ ))
done < $file
echo "Even file - $eout"
echo "Odd file - $oout"

Mas não há uma maneira de fazer isso em uma linha?

Sim, use awk, eu li.

Linhas numeradas pares:

awk 'NR % 2' filename

linhas ímpares:

awk 'NR % 2 == 1' filename

Mas isso não funciona para mim. Ambos produzem a mesma saída, de acordo com o diff. Quando comparados com o arquivo original, os dois têm metade do comprimento e as linhas com números ímpares. Estou fazendo algo errado?


6
O primeiro deve ser NR % 2 == 0, caso contrário, é equivalente ao segundo.
enzotib

Parece haver vários documentos on-line (incluindo este) que aparecem na parte superior de uma pesquisa que afirmam que NR% 2 fornece as linhas pares, o que não está correto, o ímpar porque 1% 2 = 1 = verdadeiro, 2% 2 = 0 = falso.
Deltaray 24/01/12

Respostas:


12

Como você perguntou "em uma linha":

awk '{print>sprintf("%sfile.%d",NR%2?"odd":"even",PROCINFO["pid"])}' filename

Observe que a maior parte do código é devido à sua escolha de nome de arquivo de saída sofisticado. Caso contrário, o código a seguir seria suficiente para colocar linhas ímpares na “linha 1” e linhas pares na “linha 0”:

awk '{print>"line-"NR%2}' filename

26

Eu prefiro ser compatível com POSIX, sempre que possível, então pensei em publicar este método alternativo. Costumo usá-los para alterar o texto antes dos xargspipelines.

Imprimir linhas pares numeradas,

sed -n 'n;p'

Imprimir linhas numeradas ímpares,

sed -n 'p;n'

Embora eu costumo usar awk, é um exagero para esse tipo de tarefa.


14

Isso é fácil:

 sed -n 2~2p filename

imprimirá linhas pares do nome do arquivo

sed -n 1~2p filename

imprimirá linhas com números ímpares.


11
+1, por não usar o AWK de forma extrínseca. Não é POSIX sed, mas ainda é um método sólido.
JM Becker

@TechZilla Eu não entendo "usar AWK de forma extrínseca" - o awk também é POSIX.
#

3
@ jw013: Não há nada errado awk, pessoalmente eu o uso com muita frequência. Eu nunca disse que algo não era 'POSIX' awk, estava me referindo às sedopções da resposta . Especificamente, o ~operador é uma extensão GNU, que ainda é aceitável para muitas pessoas. Em relação a 'usar o AWK , I personally believe using externamente awk' para esta tarefa simples, é um exagero. Portanto, o +1 era para concluir a tarefa sed, um utilitário mais leve que o awk.
JM Becker #

11
Alguém por favor pode explicar como ~ operator funciona aqui?
Para sempre Learner

9

Para números pares, o código deve ser

awk 'NR%2==0' filename

& para números ímpares

awk 'NR%2==1' filename

11
este é perfeito. Até funciona se você precisar obter linhas com incremento de 10, digamos que você precise reduzir um arquivo ordenado de tamanho 1 milhão para 100k. Isto é exatamente o que eu queria.
Dexter

Como você pode imprimir as colunas pares no AWK? Não consigo fazer isso funcionar gawk 'FS=",";NF%2==0' file.csv.
hhh

2

Você pode fazer isso com uma única sedchamada, sem necessidade de ler o arquivo duas vezes:

sed '$!n
w even
d' infile > odd

ou, se preferir em uma linha:

sed -e '$!n' -e 'w even' -e d infile > odd

Observe que eles não fornecerão o resultado esperado se um arquivo contiver apenas uma linha (a linha será wcopiada em evenvez de odda primeira nnão ser executada). Para evitar isso, adicione uma condição:

sed -e '$!n' -e '1!{w even' -e 'd}' infile > odd

Como funciona ? Bem, ele usa três sedcomandos:
n- se não estiver na última linha, imprima o espaço do padrão para stdout(que é redirecionado para o arquivo odd), substitua-o pela próxima linha (agora está processando uma linha par) e continue executando os comandos restantes
w- acrescente o espaço do padrão a ser arquivado even
d- exclua o espaço do padrão atual e reinicie o ciclo - o efeito colateral disso é que sednunca imprimirá automaticamente o espaço do padrão, pois nunca alcançará o final do script

Em outras palavras, né executado apenas em linhas ímpares e we dsão executados apenas em linhas pares. sednunca chega à impressão automática, a menos que, como eu disse, a entrada consista em uma única linha.


você poderia, por favor, explicar como isso funciona?
Para sempre Learner

Muito obrigado don_crissti pela sua ajuda. Sinceramente aprecio isso, votado também.
Para sempre Learner

0

Tente o seguinte:

awk '{if(NR%2){print $0 > "odd.file"}else{print $0 > "even.file"}}' filename

Você tem certeza sobre a saída dos números de registro?
manatwork

desculpe por isso, eu modifiquei para gerar as linhas inteiras.
renma

0

Eu iria perlporque gosto de perl:

perl -pe 'BEGIN{open($e,">even_lines");open($o,">odd_lines")} $. % 2 ?select $o:select $e;'

Usa o fato de que -pimplicitamente imprime, para replicar como sedfunciona - e usamos selectpara escolher qual identificador de arquivo no qual ele grava.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.