Як вибрати певні рядки (n, n + 4, n + 8, n + 12…) з файлу?


11

Вхід:

1
hgh
h2b
h4h
2
ok
koko
lkopk
3
uh
ju
nfjvn
4

Очікуваний вихід:

1
2
3
4

Отже, у вихідному файлі мені потрібно мати лише 1-е, 5-е, 9-е, 13-е значення. Як це зробити?


2
дивіться також: unix.stackexchange.com/questions/325985/… з GNU sed, ви можете зробитиsed -n '1~4p'
Sundeep

Відповіді:


28

Використання AWK:

awk '!((NR - 1) % 4)' input > output

З'ясування того, як це працює, залишається вправою для читача.


дякую за цей короткий курс awk!
darxmurf

20
NR % 4 == 1було б більш розбірливим ІМО.
Стефан Шазелас

12
Домовились @ Stéphane; це, мабуть, сумнівно з мого боку, але на питання, що стосуються домашніх завдань, я намагаюся трохи
Стівен Кітт

@StephenKitt придушує свої відповіді? Дійсно? Це не місце для цього.
дані

22

Використання split (GNU coreutils):

split -nr/1/4 input > output
  • -nгенерувати CHUNKSвихідні файли

і CHUNKSяк

  • r/K/N використовувати круговий розподіл роботів і виводити тільки Kth N на stdout без розбиття рядків / записів

1
Розум подув. Такі відповіді, тому я люблю цей SE. Спасибі!
користувач1717828

21

З GNU sed:

sed '1~4!d' < input > output

Зі стандартними sed:

sed -n 'p;n;n;n' < input > output

З 1і 4в $nі $iзмінними:

sed "$n~$i!d" # GNU only
awk -v n="$n" -v i="$i" 'NR >= n && (NR % i) == (n % i)'

7

Додавання обов'язкового рішення perl:

perl -ne 'print if $. % 4 == 1' input > output

4

Версія Python, просто для розваги:

with open('input.txt') as f:
    for i, line in enumerate(f.readlines()):
        if i%4 == 0:
            print(line.strip())

enumerate(f)повинні вміти виконувати роботу, споживаючи менше пам’яті
iruvar

@iruvar Це так акуратно! Ніколи раніше не розумів цього; буде використовуватись у майбутньому. Не соромтесь відредагувати його у цій відповіді; Я насправді не збираюсь підтримувати це оптимізацією, оскільки інші відповіді Баша (особливо цей ), безумовно, шлях.
користувач1717828

Якщо ви збираєтеся використовувати readlines(отже, урізавши весь файл в пам'ять), ви можете використовувати f.readlines()[::4]кожен четвертий рядок. Тож можна використовувати print(''.join(f.readlines()[::4])).
Нік Маттео

3

POSIX sed: у цьому методі використовується posixly sed, і тому його можна виконувати скрізь або принаймні ті набори, які поважають posix.

 $ sed -ne '
   /\n/!{
    H;s/.*//;x
   }

   :loop
       $bdone
       N;s/\n/&/4
       tdone
   bloop

   :done
   s/.//;P
 ' input.file

Ще одне програмне генерування коду sed для цілей масштабування:

$ code=$(yes n | head -n 4 | paste -sd\; | sed s/n/p/)
$ sed -ne "$code" input.file

Perl: ми заповнюємо масив A до розміру 4. Потім друкуємо його перший елемент і також очищаємо масив.

$ perl -pe '
   $A[@A] = @A ? <> : $_ while @A < 4;
   $_ = (splice @A)[0];
' input.file

1

Дзвінок за допомогою scriptname filename skip(4 у вашому випадку) Він працює, витягуючи iterрядки зверху файлу, а потім виводячи лише останню. Потім він збільшується iterна skipsі повторюється до тих пір, поки значення iterне перевищило значення linesв file.

#!/bin/bash
file="$1"
lines=`wc -l < "$file"`
skips="$2" || "4"
iter=1
while [ "$iter" -le "$lines" ]; do
 head "$file" -n $iter | tail -n 1
 iter=$(( $iter + $skips ))
done

1

Чистий баш:

mapfile -t lines < input
for (( i=0; i < ${#lines[@]}; i+=4 ))
do printf "%s\n" "${lines[$i]}"
done

mapfile - це вбудований додаток у Bash 4, який зчитує стандартний вхід у масив, названий тут lines, з одним рядком на запис. -tВаріант смужки остаточного перекладу рядка.

Якщо ви хочете надрукувати кожен четвертий рядок, починаючи з рядка 4, ви можете зробити це в одній команді, використовуючи mapfileопцію зворотного виклику -C, яка запускає наданий код кожні стільки рядків, з інтервалом, заданим символом -c. Поточний індекс масиву та наступний рядок, який буде призначений, надаються коду як аргументи.

mapfile -t -c4 -C 'printf "%.0s%s\n"' < input

Для цього використовується printfвбудований; код формату %.0sпридушує перший аргумент (індекс), тому друкується лише рядок.

Ви можете використовувати одну і ту ж команду для друку кожного четвертого рядка, починаючи з рядка 1, 2 або 3, але вам доведеться додати 3, 2 або 1 рядки до того, inputяк подавати його mapfile, що, на мою думку, є більше клопоту, ніж варто .

Це також працює:

mapfile -t lines < input
printf "%s%.0s%.0s%.0s\n" "${lines[@]}"

Тут використовується одночасно printfчотири записи масиву lines, тільки друкується перший і пропускається інші три %.0s. Мені це не подобається, оскільки вам доведеться вручну поспілкуватися з рядком формату для різних інтервалів або початкових точок.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.