Stampa linee dispari, stampa linee pari


18

Voglio stampare le righe dispari e pari dai file.

Ho trovato questo script di shell che utilizza echo.

#!/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"

Ma non c'è un modo per farlo in una riga?

Sì, usa awk, ho letto.

Linee pari:

awk 'NR % 2' filename

righe dispari:

awk 'NR % 2 == 1' filename

Ma non funziona per me. Entrambi producono lo stesso output, secondo diff. Rispetto al file originale, sono in effetti entrambi lunghi la metà e contengono entrambe le righe dispari. Sto facendo qualcosa di sbagliato?


6
Il primo dovrebbe essere NR % 2 == 0, altrimenti è equivalente al secondo.
enzotib,

Sembra che ci siano diversi documenti online (incluso questo) che compaiono nella parte superiore di una ricerca in cui si afferma che NR% 2 ti dà le linee numerate pari, il che non è corretto, ti dà lo strano perché 1% 2 = 1 = vero, 2% 2 = 0 = falso.
deltaray,

Risposte:


12

Come hai chiesto "in una riga":

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

Si noti che la maggior parte del codice è dovuta alla scelta del nome del file di output di fantasia. Altrimenti il ​​seguente codice sarebbe sufficiente per inserire le righe dispari in "linea-1" e le righe pari in "linea-0":

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

26

Preferisco essere compatibile con POSIX, quando possibile, quindi ho pensato di pubblicare questo metodo alternativo. Li uso spesso per manipolare il testo, primaxargs condutture.

Stampa linee pari,

sed -n 'n;p'

Stampa righe numerate dispari,

sed -n 'p;n'

Anche se lo uso spesso awk, è eccessivo per questo tipo di attività.


14

Questo è facile:

 sed -n 2~2p filename

stamperà le linee pari dal nome del file

sed -n 1~2p filename

stamperà righe dispari.


1
+1, per non utilizzare AWK in modo estraneo. Non POSIX sed, ma è ancora un metodo solido.
JM Becker,

@TechZilla Non capisco "usare AWK in modo estraneo" - anche awk è POSIX.
jw013,

3
@ jw013: non c'è niente di sbagliato awk, personalmente lo uso molto spesso. Non ho mai detto nulla di "POSIX" awk, mi riferivo alle sedopzioni della risposta . In particolare l' ~operatore, è un'estensione GNU, che è ancora accettabile per molte persone. , I personally believe using Considerare "l'utilizzo di AWK estraneo a awk" per questo semplice compito è eccessivo. Quindi il +1 era per il completamento dell'attività con sedun'utilità più leggera di awk.
JM Becker,

1
Qualcuno può spiegare come ~ operatore lavora qui?
Forever Learner,

9

Per i numeri pari dovrebbe essere il codice

awk 'NR%2==0' filename

e per i numeri dispari

awk 'NR%2==1' filename

1
questo è perfetto. Funziona anche se hai bisogno di ottenere righe in incrementi di 10, supponi di dover ridurre un file ordinato di dimensioni da 1 milione a 100k. Questo è esattamente quello che volevo.
Dexter,

Come è possibile stampare le colonne con numero pari in AWK? Non riesco a farlo funzionare gawk 'FS=",";NF%2==0' file.csv.
hhh,

2

Puoi farlo con una sola sedchiamata, non è necessario leggere il file due volte:

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

oppure, se preferisci in una riga:

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

Si noti che questi non daranno il risultato atteso se un file contiene solo una riga (la riga verrà wtracciata evenanziché oddcome priman non eseguita). Per evitarlo, aggiungi una condizione:

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

Come funziona ? Bene, usa tre sedcomandi:
n- se non sull'ultima riga stampa lo spazio del modello su stdout(che viene reindirizzato al file odd), sostituiscilo con la riga successiva (quindi ora sta elaborando una linea pari) e continua ad eseguire i comandi rimanenti
w- append lo spazio di pattern su file even
d- elimina lo spazio di pattern corrente e riavvia il ciclo - l'effetto collaterale di questo è che sednon stampa automaticamente lo spazio di pattern poiché non raggiunge mai la fine dello script

In altre parole, nviene eseguito solo su righe dispari we dviene eseguito solo su righe pari. sednon arriva mai alla stampa automatica a meno che, come ho detto, l'input sia costituito da una sola riga.


potresti per favore elaborare come funziona?
Forever Learner,

Grazie mille don_crissti per il tuo aiuto. Sinceramente lo apprezzo, anche votato.
Forever Learner,

0

Prova questo:

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

Sei sicuro di emettere i numeri dei record?
arte

scusatemi, l'ho modificato per produrre l'intera riga.
renma,

0

Vorrei andare perlperché mi piace perl:

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

Usa il fatto che -pstampa implicitamente, per replicare come sedfunziona - e usiamo selectper scegliere quale file gestire in cui scrive.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.