Drukuj linie nieparzyste, drukuj linie parzyste

18

Chcę wydrukować nieparzyste i parzyste linie z plików.

Znalazłem ten skrypt powłoki, który wykorzystuje 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"

Ale czy nie ma sposobu, aby to zrobić w jednym wierszu?

Tak, używam awk, czytam.

Linie parzyste:

awk 'NR % 2' filename

linie nieparzyste:

awk 'NR % 2 == 1' filename

Ale to nie działa dla mnie. Oba wytwarzają tę samą moc wyjściową, zgodnie z różnicą. W porównaniu do oryginalnego pliku oba są rzeczywiście o połowę dłuższe i oba zawierają wiersze o nieparzystych numerach. czy robię coś źle?

ixtmixilix
źródło
6
Pierwsza powinna być NR % 2 == 0, w przeciwnym razie jest równoważna drugiej.
enzotib,
Wydaje się, że jest kilka dokumentów online (w tym ten), które pojawiają się na początku wyszukiwania, które stwierdzają, że NR% 2 daje ci parzyste linie, co nie jest poprawne, daje ci dziwne, ponieważ 1% 2 = 1 = prawda, 2% 2 = 0 = fałsz.
deltaray

Odpowiedzi:

12

Jak zapytałeś „w jednej linii”:

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

Zauważ, że większość kodu wynika z twojego fantazyjnego wyboru nazwy pliku wyjściowego. W przeciwnym razie następujący kod wystarczyłby, aby wstawić nieparzyste linie w „linii-1”, a nawet linie w „linii-0”:

awk '{print>"line-"NR%2}' filename
człowiek w pracy
źródło
26

W miarę możliwości wolę być zgodny z POSIX, więc pomyślałem, że opublikuję tę alternatywną metodę. Często używam ich do zmieniania tekstu przed xargspotokami.

Drukuj linie parzyste,

sed -n 'n;p'

Drukuj linie nieparzyste,

sed -n 'p;n'

Chociaż często używam awk, dla tego typu zadań jest to przesada.

JM Becker
źródło
14

To łatwe:

 sed -n 2~2p filename

wypisze linie parzyste z nazwy pliku

sed -n 1~2p filename

wypisze linie nieparzyste.

neuron34
źródło
1
+1 za nieużywanie AWK w inny sposób. Nie POSIX sed, ale wciąż jest to solidna metoda.
JM Becker
@TechZilla Nie rozumiem „korzystania z AWK w inny sposób” - awk to również POSIX.
jw013
3
@ jw013: Nie ma w tym nic złego awk, osobiście używam go bardzo często. Nigdy nie mówiłem, że coś jest „nie POSIX” awk, miałem na myśli sedopcje odpowiedzi . W szczególności ~operator, jest to rozszerzenie GNU, które nadal jest akceptowalne dla wielu osób. Jeśli chodzi o „używanie AWK z zewnątrz , I personally believe using awk” do tego prostego zadania, to przesada. Tak więc +1 służyło do wykonania zadania przy sedużyciu lżejszego narzędzia niż awk.
JM Becker
1
Czy ktoś może wyjaśnić, jak działa ~ operator?
Forever Learner
9

W przypadku liczb parzystych kod powinien być

awk 'NR%2==0' filename

i dla liczb nieparzystych

awk 'NR%2==1' filename
Neel
źródło
1
ten jest idealny. Działa nawet, jeśli chcesz uzyskać wiersze w odstępach co 10, powiedz, że musisz zmniejszyć zamówiony plik o wielkości 1 miliona do 100k. Właśnie tego chciałem.
Dexter
Jak wydrukować kolumny parzyste w AWK? Nie mogę tego uruchomić gawk 'FS=",";NF%2==0' file.csv.
hhh
2

Możesz to zrobić za pomocą pojedynczego sedwywołania, nie musisz dwa razy czytać pliku:

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

lub, jeśli wolisz w jednym wierszu:

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

Zauważ, że nie dadzą one oczekiwanego rezultatu, jeśli plik zawiera tylko jedną linię (linia zostanie wprzekreślona evenzamiast, oddponieważ pierwsza nnie zostanie wykonana). Aby tego uniknąć, dodaj warunek:

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

Jak to działa ? Cóż, używa trzech sedpoleceń:
n- jeśli nie w ostatnim wierszu, wypisz obszar wzorców do stdout(który jest przekierowany do pliku odd), zamień go na następny wiersz (teraz przetwarza linię parzystą) i kontynuuj wykonywanie pozostałych poleceń
w- dołącz przestrzeń wzorów do pliku even
d- usuń bieżącą przestrzeń wzorów i uruchom ponownie cykl - efektem ubocznym jest to, że sednigdy nie wydrukuje automatycznie obszaru wzorów, ponieważ nigdy nie osiągnie końca skryptu

Innymi słowy, njest wykonywany tylko na liniach nieparzystych wi djest wykonywany tylko na liniach parzystych. sednigdy nie drukuje się automatycznie, chyba że, jak powiedziałem, dane wejściowe składają się z jednej linii.

don_crissti
źródło
czy mógłbyś wyjaśnić, jak to działa?
Forever Learner,
Wielkie dzięki don_crissti za pomoc. Szczerze to doceniam, również pozytywnie oceniany.
Forever Learner
0

Spróbuj tego:

awk '{if(NR%2){print $0 > "odd.file"}else{print $0 > "even.file"}}' filename
renma
źródło
Czy jesteś pewien, że wyprowadzasz numery rekordów?
manatwork,
przepraszam za to, zmodyfikowałem go tak, aby wyświetlał całe linie.
renma,
0

Wybrałbym, perlbo lubię perl:

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

Wykorzystuje fakt, że -pniejawnie się drukuje, aby zreplikować sposób seddziałania - i my selectwybieramy uchwyt pliku, do którego zapisuje.

Sobrique
źródło