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?
sed -n '16224,16482p;16483q' filename > newfile
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).
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.
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
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.
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
Perl -ne 'print if 16224..16482' file.txt > new_file.txt
# print section of file based on line numbers
sed -n '16224 ,16482p' # method 1
sed '16224,16482!d' # method 2
sed -n '16224,16482p' < dump.sql
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.
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.
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. ;-)
mở tệp đầu ra mới, lưu ctl-y
Hãy để tôi xem những gì đang xảy ra.
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
Sử dụng Ruby:
Ruby -ne 'puts "#{$.}: #{$_}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf
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.
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.
Đ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
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
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).
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
Đứ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.
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: