it-swarm-vi.tech

Làm cách nào tôi có thể trích xuất một phạm vi dòng được xác định trước từ tệp văn bản trên Unix?

Tôi có một bãi chứa SQL dòng ~ 23000 chứa một số cơ sở dữ liệu có giá trị dữ liệu. Tôi cần trích xuất một phần nhất định của tệp này (nghĩa là dữ liệu cho một cơ sở dữ liệu) và đặt nó vào một tệp mới. Tôi biết cả số dòng bắt đầu và số cuối của dữ liệu mà tôi muốn.

Có ai biết một lệnh Unix (hoặc chuỗi lệnh) để trích xuất tất cả các dòng từ một tệp giữa dòng say 16224 và 16482 và sau đó chuyển hướng chúng thành một tệp mới không?

447
Adam J. Forster
sed -n '16224,16482p;16483q' filename > newfile

Từ hướng dẫn sử dụng sed :

p - In ra không gian mẫu (đến đầu ra tiêu chuẩn). Lệnh này thường chỉ được sử dụng cùng với tùy chọn dòng lệnh -n.

n - Nếu tự động in không bị tắt, hãy in không gian mẫu, sau đó, bất kể, thay thế không gian mẫu bằng dòng đầu vào tiếp theo. Nếu không còn đầu vào sau đó thoát ra mà không xử lý nữa các lệnh.

q - Thoát sed mà không xử lý thêm bất kỳ lệnh hoặc đầu vào nào . Lưu ý rằng không gian mẫu hiện tại được in nếu tự động in không bị tắt với tùy chọn -n.

Địa chỉ trong tập lệnh sed có thể ở bất kỳ dạng nào sau đây:

con số Chỉ định số dòng sẽ chỉ khớp với dòng đó trong đầu vào.

Một phạm vi địa chỉ có thể được chỉ định bằng cách chỉ định hai địa chỉ cách nhau bằng dấu phẩy (,). Một phạm vi địa chỉ khớp với các dòng bắt đầu từ trong đó địa chỉ đầu tiên khớp và tiếp tục cho đến địa chỉ thứ hai khớp địa chỉ (bao gồm).

681
boxxar
sed -n '16224,16482 p' orig-data-file > new-file

Trong đó 16224,16482 là số dòng bắt đầu và số dòng kết thúc, đã bao gồm. Đây là 1 chỉ mục. -n ngăn chặn tiếng vang đầu vào là đầu ra mà bạn rõ ràng không muốn; các con số biểu thị phạm vi của các dòng để thực hiện lệnh sau; lệnh p in ra các dòng có liên quan.

195
JXG

Khá đơn giản bằng cách sử dụng đầu/đuôi:

head -16482 in.sql | tail -258 > out.sql

sử dụng sed:

sed -n '16482,16482p' in.sql > out.sql

sử dụng awk:

awk 'NR>=10&&NR<=20' in.sql > out.sql
78
manveru

Bạn có thể sử dụng 'vi' và sau đó là lệnh sau:

:16224,16482w!/tmp/some-file

Cách khác: 

cat file | head -n 16482 | tail -n 258

EDIT: - Chỉ cần thêm lời giải thích, bạn sử dụng head -n 16482 để hiển thị 16482 dòng đầu tiên sau đó sử dụng tail -n 258 để có được 258 dòng cuối cùng từ đầu ra đầu tiên. 

25
Mark Janssen

Có một cách tiếp cận khác với awk:

awk 'NR==16224, NR==16482' file

Nếu tệp rất lớn, có thể tốt cho exit sau khi đọc dòng mong muốn cuối cùng. Bằng cách này, nó sẽ không cần thiết đọc tệp cho đến cuối:

awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file
20
fedorqui
Perl -ne 'print if 16224..16482' file.txt > new_file.txt
14
mmaibaum
 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2
8
Cetra

sed -n '16224,16482p' < dump.sql

5
cubex
cat dump.txt | head -16224 | tail -258

nên làm thủ thuật. Nhược điểm của phương pháp này là bạn cần thực hiện số học để xác định đối số cho đuôi và tính toán xem bạn có muốn 'giữa' bao gồm dòng kết thúc hay không.

5
JP Lodine

Nhanh chóng và hèn hạ:

head -16428 < file.in | tail -259 > file.out

Có lẽ không phải là cách tốt nhất để làm điều đó nhưng nó nên hoạt động.

BTW: 259 = 16482-16224 + 1.

3
jan.vdbergh

Tôi đã định đăng mẹo lừa đầu/đuôi, nhưng thực sự có lẽ tôi chỉ cần kích hoạt emacs. ;-)

  1. esc-x goto-line ret 16224
  2. dấu (ctrl-space)
  3. esc-x goto-line ret 16482
  4. esc-w

mở tệp đầu ra mới, lưu ctl-y

Hãy để tôi xem những gì đang xảy ra.

3
sammyo

Thậm chí chúng ta có thể làm điều này để kiểm tra tại dòng lệnh:

cat filename|sed 'n1,n2!d' > abc.txt

Ví dụ:

cat foo.pl|sed '100,200!d' > abc.txt
2
Chinmoy Padhi

Sử dụng Ruby:

Ruby -ne 'puts "#{$.}: #{$_}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf
2
Carl Blakeley

Tôi sẽ dùng:

awk 'FNR >= 16224 && FNR <= 16482' my_file > extracted.txt

FNR chứa số bản ghi (dòng) của dòng được đọc từ tệp.

2
Paddy3118

Tôi đã viết một chương trình Haskell có tên splitter thực hiện chính xác điều này: có đọc qua bài đăng trên blog phát hành của tôi .

Bạn có thể sử dụng chương trình như sau:

$ cat somefile | splitter 16224-16482

Và đó là tất cả những gì có nó. Bạn sẽ cần Haskell để cài đặt nó. Chỉ:

$ cabal install splitter

Và bạn đã hoàn thành. Tôi hy vọng rằng bạn thấy chương trình này hữu ích.

2
Robert Massaioli

Điều này có thể làm việc cho bạn (GNU sed):

sed -ne '16224,16482w newfile' -e '16482q' file

hoặc lợi dụng bash:

sed -n $'16224,16482w newfile\n16482q' file
1
potong

Tôi đã viết một tập lệnh bash nhỏ mà bạn có thể chạy từ dòng lệnh của mình, miễn là bạn cập nhật PATH của mình để bao gồm thư mục của nó (hoặc bạn có thể đặt nó trong một thư mục đã có trong PATH).

Cách sử dụng: $ pinch tên tệp bắt đầu dòng cuối

#!/bin/bash
# Display line number ranges of a file to the terminal.
# Usage: $ pinch filename start-line end-line
# By Evan J. Coon

FILENAME=$1
START=$2
END=$3

ERROR="[PINCH ERROR]"

# Check that the number of arguments is 3
if [ $# -lt 3 ]; then
    echo "$ERROR Need three arguments: Filename Start-line End-line"
    exit 1
fi

# Check that the file exists.
if [ ! -f "$FILENAME" ]; then
    echo -e "$ERROR File does not exist. \n\t$FILENAME"
    exit 1
fi

# Check that start-line is not greater than end-line
if [ "$START" -gt "$END" ]; then
    echo -e "$ERROR Start line is greater than End line."
    exit 1
fi

# Check that start-line is positive.
if [ "$START" -lt 0 ]; then
    echo -e "$ERROR Start line is less than 0."
    exit 1
fi

# Check that end-line is positive.
if [ "$END" -lt 0 ]; then
    echo -e "$ERROR End line is less than 0."
    exit 1
fi

NUMOFLINES=$(wc -l < "$FILENAME")

# Check that end-line is not greater than the number of lines in the file.
if [ "$END" -gt "$NUMOFLINES" ]; then
    echo -e "$ERROR End line is greater than number of lines in file."
    exit 1
fi

# The distance from the end of the file to end-line
ENDDIFF=$(( NUMOFLINES - END ))

# For larger files, this will run more quickly. If the distance from the
# end of the file to the end-line is less than the distance from the
# start of the file to the start-line, then start pinching from the
# bottom as opposed to the top.
if [ "$START" -lt "$ENDDIFF" ]; then
    < "$FILENAME" head -n $END | tail -n +$START
else
    < "$FILENAME" tail -n +$START | head -n $(( END-START+1 ))
fi

# Success
exit 0
1
Nerdfighter

Tôi muốn làm điều tương tự từ một tập lệnh bằng cách sử dụng một biến và đạt được nó bằng cách đặt dấu ngoặc kép quanh biến $ để tách tên biến khỏi p:

sed -n "$first","$count"p imagelist.txt >"$imageblock"

Tôi muốn chia một danh sách thành các thư mục riêng biệt và tìm thấy câu hỏi ban đầu và trả lời một bước hữu ích. (lệnh split không phải là một tùy chọn trên hệ điều hành cũ mà tôi phải chuyển mã sang).

1
KevinY

Vì chúng ta đang nói về việc trích xuất các dòng văn bản từ một tệp văn bản, tôi sẽ đưa ra một trường hợp đặc biệt khi bạn muốn trích xuất tất cả các dòng khớp với một mẫu nhất định. 

myfile content:
=====================
line1 not needed
line2 also discarded
[Data]
first data line
second data line
=====================
sed -n '/Data/,$p' myfile

Sẽ in dòng [Dữ liệu] và phần còn lại. Nếu bạn muốn văn bản từ dòng1 đến mẫu, bạn nhập: sed -n '1,/Data/p' myfile. Hơn nữa, nếu bạn biết hai mẫu (tốt hơn là duy nhất trong văn bản của bạn), cả dòng đầu và cuối của phạm vi có thể được chỉ định bằng các kết quả khớp.

sed -n '/BEGIN_MARK/,/END_MARK/p' myfile
0
Kemin Zhou

Đứng trên vai của boxxar, tôi thích điều này:

sed -n '<first line>,$p;<last line>q' input

ví dụ.

sed -n '16224,$p;16482q' input

$ có nghĩa là "dòng cuối cùng", vì vậy lệnh đầu tiên tạo sed in tất cả các dòng bắt đầu bằng dòng 16224 và lệnh thứ hai tạo sed thoát sau in dòng 16428. (Thêm 1 cho phạm vi q- trong giải pháp của boxxar dường như là không cần thiết.)

Tôi thích biến thể này vì tôi không cần chỉ định số dòng kết thúc hai lần. Và tôi đã đo được rằng sử dụng $ không có tác động bất lợi đến hiệu suất.

0
Tilman Vogel

Các -n trong câu trả lời chấp nhận làm việc. Đây là một cách khác trong trường hợp bạn nghiêng.

cat $filename | sed "${linenum}p;d";

Điều này thực hiện như sau:

  1. ống trong nội dung của tệp (hoặc nguồn cấp dữ liệu trong văn bản theo cách bạn muốn).
  2. sed chọn dòng đã cho, in nó
  3. d được yêu cầu xóa các dòng, nếu không sed sẽ cho rằng tất cả các dòng cuối cùng sẽ được in. tức là không có d, bạn sẽ nhận được tất cả các dòng được in bởi dòng đã chọn được in hai lần vì bạn có phần p $ {linenum} yêu cầu in. Tôi khá chắc chắn rằng - về cơ bản là làm điều tương tự như d ở đây.
0
ThinkBonobo