Печать нечетных строк, печать четных строк


18

Я хочу напечатать строки с нечетными и четными номерами из файлов.

Я нашел этот сценарий оболочки, который использует эхо.

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

Но разве нет способа сделать это в одну строку?

Да, используйте awk, я прочитал.

Четные строки:

awk 'NR % 2' filename

нечетные строки:

awk 'NR % 2 == 1' filename

Но это не работает для меня. Оба производят одинаковый выход, согласно diff. По сравнению с исходным файлом они действительно вдвое длиннее и содержат строки с нечетными номерами. Я делаю что-то неправильно?


6
Первый должен быть NR % 2 == 0, в противном случае он эквивалентен второму.
энзотиб

Похоже, в Интернете есть несколько документов (включая этот), которые отображаются в верхней части поиска и утверждают, что NR% 2 дает четные строки, что неверно, а нечетное, поскольку 1% 2 = 1 = true, 2% 2 = 0 = false.
Deltaray

Ответы:


12

Как вы спросили «в одну строку»:

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

Обратите внимание, что большая часть кода связана с вашим необычным выбором имени выходного файла. В противном случае следующего кода было бы достаточно, чтобы поместить нечетные строки в «line-1» и четные строки в «line-0»:

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

26

Я предпочитаю быть POSIX-совместимым, когда это возможно, поэтому я решил опубликовать этот альтернативный метод. Я часто использую их для искажения текста перед xargsконвейерами.

Печать четных линий,

sed -n 'n;p'

Печать нечетных линий,

sed -n 'p;n'

Хотя я часто использую awk, это слишком много для такого рода задач.


14

Это легко:

 sed -n 2~2p filename

будет печатать четные строки из имени файла

sed -n 1~2p filename

напечатает нечетные строки.


1
+1, за неиспользование AWK посторонним. Не POSIX, но это все еще твердый метод.
JM Becker

@TechZilla Я не понимаю, «использовать AWK извне» - awk также POSIX.
jw013

3
@ jw013: Ничего плохого awk, лично я использую его очень часто. Я никогда не говорил, что что-то было «не POSIX» awk, я имел в виду sedварианты ответа . В частности, ~оператор, это расширение GNU, которое все еще приемлемо для многих людей. Относительно «использовать AWK посторонним образом , I personally believe using awk» для этой простой задачи - это излишне. Таким образом, +1 был для выполнения задачи с sedболее легкой утилитой, чем awk.
JM Becker

1
Может кто-нибудь объяснить, пожалуйста, как работает оператор ~?
Forever Learner

9

Для четных чисел код должен быть

awk 'NR%2==0' filename

& для нечетных чисел

awk 'NR%2==1' filename

1
этот идеален. Даже работает, если вам нужно получить строки с шагом 10, скажем, вам нужно уменьшить упорядоченный файл размером от 1 миллиона до 100 тысяч. Это именно то, что я хотел.
Декстер

Как вы можете распечатать четные столбцы в AWK? Я не могу заставить это работать gawk 'FS=",";NF%2==0' file.csv.
HHH

2

Вы можете сделать это одним sedвызовом, не нужно читать файл дважды:

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

или, если вы предпочитаете в одну строку:

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

Обратите внимание, что они не дадут ожидаемого результата, если файл содержит только одну строку (строка будет wзаписана evenвместо того, oddчтобы nне выполнить первую ). Чтобы избежать этого, добавьте условие:

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

Как это устроено ? Хорошо, он использует три sedкоманды:
n- если не в последней строке, выведите пространство шаблона в stdout(которое перенаправлено в файл odd), замените его следующей строкой (так что теперь он обрабатывает четную строку) и продолжите выполнение оставшихся команд
w- добавьте пространство шаблона в файл even
d- удалите текущее пространство шаблона и перезапустите цикл - побочный эффект этого состоит в том, sedчто никогда не будет автоматически печатать пространство шаблона, поскольку оно никогда не достигнет конца сценария

Другими словами, nвыполняется только на нечетных строках и wи dвыполняется только на четных строках. sedникогда не попадает в автопечать, если, как я уже сказал, ввод не состоит из одной строки.


не могли бы вы уточнить, как это работает?
Forever Learner

Большое спасибо don_crissti за вашу помощь. Искренне ценю, проголосовал также.
Forever Learner

0

Попробуй это:

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

Вы уверены, что выводите номера записей?
Манатворк

извините за это, я изменил его для вывода целых строк.
Ренма

0

Я бы пошел с, perlпотому что мне нравится perl:

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

Использует тот факт, что -pнеявно печатает, чтобы реплицировать, как sedработает - и мы используем, selectчтобы выбрать дескриптор файла, в который он пишет.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.