Làm cách nào để chọn một số dòng nhất định (n, n + 4, n + 8, n + 12 12) từ tệp?


Câu trả lời:


28

Sử dụng AWK:

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

Tìm hiểu làm thế nào điều này hoạt động là một bài tập cho người đọc.


cảm ơn vì khóa học awk ngắn này!
darxmurf

20
NR % 4 == 1IMO dễ đọc hơn.
Stéphane Chazelas

12
Đồng ý @ Stéphane; điều này có lẽ là nghi vấn về phía tôi, nhưng đối với các câu hỏi có khả năng làm bài tập về nhà, tôi cố gắng che giấu câu trả lời của mình một chút ...
Stephen Kitt

@StephenKitt làm xáo trộn câu trả lời của bạn? Có thật không? Đây không phải là nơi để làm điều đó.
dữ liệu

22

Sử dụng split (GNU coreutils):

split -nr/1/4 input > output
  • -ntạo CHUNKStập tin đầu ra

CHUNKSnhư

  • r/K/N sử dụng phân phối vòng tròn và chỉ xuất Kth của N để xuất chuẩn mà không tách dòng / bản ghi

1
Tâm thổi. Câu trả lời như thế này là lý do tại sao tôi yêu SE này. Cảm ơn!
dùng1717828

21

Với GNU sed:

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

Với tiêu chuẩn sed:

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

Với 14trong $n$icác biến:

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

7

Thêm giải pháp perl bắt buộc:

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

4

Phiên bản Python, chỉ để giải trí:

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

enumerate(f)sẽ có thể thực hiện công việc trong khi tiêu thụ ít bộ nhớ hơn
iruvar

@iruvar Thật là gọn gàng! Chưa bao giờ nhận ra điều đó trước đây; sẽ được sử dụng trong tương lai. Hãy thoải mái chỉnh sửa nó thành câu trả lời này; Tôi thực sự sẽ không duy trì nó với sự tối ưu hóa vì các câu trả lời khác của Bash (đặc biệt là câu trả lời này ) chắc chắn là cách để đi.
dùng1717828

Nếu bạn sẽ sử dụng readlines(do đó đưa toàn bộ tệp vào bộ nhớ), bạn có thể sử dụng f.readlines()[::4]để nhận mọi dòng thứ tư. Vì vậy, bạn có thể sử dụng print(''.join(f.readlines()[::4])).
Nick Matteo

3

POSIX sed: phương pháp này sử dụng sed posixly và do đó có thể được chạy ở mọi nơi, hoặc ít nhất là những sed đó tôn trọng posix.

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

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

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

Một cái khác là tạo mã sed lập trình cho mục đích mở rộng:

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

Perl: chúng tôi điền vào mảng A cho đến khi nó có kích thước 4. Sau đó, chúng tôi in phần tử đầu tiên của nó và cũng xóa mảng.

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

1

Gọi với scriptname filename skip(4 trong trường hợp của bạn) Nó hoạt động bằng cách kéo itercác dòng từ đầu tệp và sau đó chỉ xuất ra cuối cùng. Nó sau đó từng bước iterbởi skipsvà lặp đi lặp lại chừng nào giá trị của iterkhông vượt quá linestrong 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

Bash thuần túy:

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

mapfile là một nội dung được thêm vào trong Bash 4, đọc đầu vào tiêu chuẩn vào một mảng, được đặt tên ở đây lines, với một dòng trên mỗi mục nhập. Các -ttùy chọn dải các dòng mới cuối cùng.

Nếu bạn muốn in mọi dòng thứ tư bắt đầu từ dòng 4, thì bạn có thể thực hiện điều đó trong một lệnh bằng mapfiletùy chọn gọi lại -C, chạy mã được cung cấp mỗi rất nhiều dòng, với khoảng thời gian được cung cấp bởi -c. Chỉ mục mảng hiện tại và dòng tiếp theo được gán được cung cấp cho mã dưới dạng đối số.

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

Điều này sử dụng printfnội dung; mã định dạng %.0sngăn chặn đối số đầu tiên (chỉ mục), do đó chỉ có dòng được in.

Bạn có thể sử dụng cùng một lệnh để in mọi dòng thứ tư bắt đầu từ dòng 1, 2 hoặc 3, nhưng bạn phải đặt trước 3, 2 hoặc 1 dòng inputtrước khi đưa nó vào mapfile, điều mà tôi nghĩ là rắc rối hơn giá trị của nó .

Điều này cũng hoạt động:

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

Ở đây, printftiêu thụ bốn mục của mảng linestại một thời điểm, chỉ in lần đầu tiên và bỏ qua ba mục còn lại với %.0s. Tôi không thích điều này vì bạn phải tự chỉnh sửa chuỗi định dạng cho các khoảng thời gian hoặc điểm bắt đầu khác nhau.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.