Làm cách nào để xóa n dòng đầu tiên và dòng cuối cùng của tệp bằng lệnh shell?


31

Tôi có một tệp có tên Element_querychứa kết quả của một truy vấn:

SQL> select count (*) from element;

[Output of the query which I want to keep in my file]

SQL> spool off;

Tôi muốn xóa dòng thứ 1 và dòng cuối bằng lệnh shell.


2
Bạn có lẽ tốt nhất nên sửa lỗi này trong SQL * Plus; thay vì tạo một tệp và sau đó cố gắng cắt bớt những thứ bạn không muốn, bạn chỉ có thể nói với SQL * Plus không tạo ra những thứ đó để bắt đầu. Một cách tiếp cận được mô tả trong phần "Tạo tệp phẳng" tại docs.oracle.com/cd/A84870_01/doc/sqlplus.816/a75664/ch44.htm ; một cách tiếp cận khác được mô tả tại stackoverflow.com/q/2299375/978917 .
ruakh

Câu trả lời:


48

Sử dụng GNU sed:

sed -i '1d;$d' Element_query

Làm thế nào nó hoạt động :

  • -itùy chọn chỉnh sửa tập tin chính nó. Bạn cũng có thể xóa tùy chọn đó và chuyển hướng đầu ra sang một tệp mới hoặc một lệnh khác nếu bạn muốn.
  • 1dxóa dòng đầu tiên ( 1chỉ hành động trên dòng đầu tiên, dđể xóa nó)
  • $dxóa dòng cuối cùng ( $chỉ hành động trên dòng cuối cùng, dđể xóa nó)

Đi xa hơn :

  • Bạn cũng có thể xóa một phạm vi. Ví dụ, 1,5dsẽ xóa 5 dòng đầu tiên.
  • Bạn cũng có thể xóa mọi dòng bắt đầu bằng SQL>cách sử dụng câu lệnh/^SQL> /d
  • Bạn có thể xóa mọi dòng trống với /^$/d
  • Cuối cùng, bạn có thể kết hợp bất kỳ câu lệnh nào bằng cách tách chúng bằng dấu chấm phẩy ( statement1;statement2;satement3;...) hoặc bằng cách chỉ định chúng riêng biệt trên dòng lệnh ( -e 'statement1' -e 'statement 2' ...)

Nếu dòng thứ 3 của nó bị xóa ... thì tôi phải sử dụng 3d thay cho 1d? nếu dòng thứ 3 của nó từ cuối cùng để xóa ... thì lệnh đó sẽ là gì?
pmaipmui

Làm thế nào để xóa dòng thứ 3 từ dòng cuối cùng bằng cách sử dụng các lệnh shell?
pmaipmui

@Nainita Bạn có thể chỉ định một phạm vi ( 1,3dsẽ xóa ba dòng đầu tiên) nhưng cuối cùng thì khó khăn hơn một chút. Tùy thuộc vào những gì bạn muốn, bạn có thể tốt hơn bằng cách sử dụng điều này: sed -i '/^SQL> /d' Element_queryđể xóa các dòng bắt đầu SQL> bất kể nó nằm ở đâu trong tệp.
user43791

@Nainita - xem câu trả lời của tôi ở đây để biết số lượng đuôi tùy ý - nó cung cấp hai giải pháp cho việc tước các dòng đếm liên quan đến cuối tệp. Một là một sedlớp lót - sẽ hoạt động để tước số lượng dòng tùy ý từ đầu đuôi của tệp, Mặc dù vậy, miễn là đầu vào là một tệp thông thường, chỉ để nhóm một đầu vào duy nhất qua hai headquy trình - đó là cách nhanh nhất để làm điều này thường.
mikeerv

Tôi đã sử dụng sed -i '1d' table-backup.sqlđể xóa dòng đầu tiên của tệp văn bản sql
David Thomas

8

cái đầu; cái đầu

{   head -n[num] >/dev/null
    head -n[num]
}  <infile >outfile

Với phần trên, bạn có thể chỉ định số dòng đầu tiên để loại bỏ phần đầu của đầu ra w / headlệnh đầu tiên và số dòng để ghi vào outfilephần thứ hai. Nó cũng thường sẽ làm điều này nhanh hơn sed- đặc biệt là khi đầu vào lớn - mặc dù yêu cầu hai lệnh. Trong trường hợp sedchắc chắn nên được ưa chuộng hơn, mặc dù là trong trường hợp đó <infilekhông thường xuyên, lseekable tập tin - bởi vì điều này sẽ thường không làm việc như dự định trong trường hợp đó, nhưng sedcó thể xử lý tất cả những thay đổi đầu ra trong một quá trình duy nhất, kịch bản.

Với GNU, headbạn cũng có thể sử dụng -dạng phủ định cho [num]lệnh thứ hai. Trong trường hợp đó, lệnh sau sẽ loại bỏ các dòng đầu tiên và cuối cùng khỏi đầu vào:

{   head -n1 >/dev/null
    head -n-1
}  <infile >outfile

HOẶC với POSIX sed:

Ví dụ, tôi đã đọc một đầu vào gồm 20 dòng và tôi muốn loại bỏ 3 dòng đầu tiên và 7 dòng cuối cùng. Nếu tôi quyết tâm làm như vậy sed, tôi sẽ làm điều đó với bộ đệm đuôi. Trước tiên tôi sẽ cộng ba và bảy với tổng số dải là mười và sau đó làm:

seq 20 | sed -ne:n -e '3d;N;1,10bn' -eP\;D

Đó là một ví dụ loại bỏ 3 dòng đầu tiên và 7 dòng cuối cùng từ đầu vào. Ý tưởng là bạn có thể đệm bao nhiêu dòng mà bạn muốn tách khỏi đuôi đầu vào trong không gian mẫu trên một ngăn xếp nhưng chỉ Print cái đầu tiên trong số này cho mỗi dòng được kéo vào.

  • Trên các dòng 1,10 sed Pgợi ý không có gì vì đối với mỗi dòng, nó xếp chồng đầu vào trong không gian mẫu theo từng dòng trong một bvòng lặp trang trại.
  • Trên dòng thứ 3, tất cả các sedngăn xếp đều bị dxóa - và vì vậy 3 dòng đầu tiên bị tước khỏi đầu ra trong một cú trượt.
  • Khi sedđạt đến $dòng đầu vào cuối cùng và cố gắng kéo vào phần mở rộng, Nnó chạm EOF và dừng xử lý hoàn toàn. Nhưng tại thời điểm đó, không gian mẫu chứa tất cả các dòng 14,20- không có dòng nào trong số đó chưa được tô màu Pvà không bao giờ.
  • Trên tất cả các sed Pgợi ý dòng khác chỉ tối đa \newline xuất hiện đầu tiên trong không gian mẫu và Dbỏ qua tương tự trước khi bắt đầu một chu kỳ mới với những gì còn lại - hoặc 6 dòng đầu vào tiếp theo. Dòng thứ 7 được nối lại vào ngăn xếp với Nlệnh ext trong chu kỳ mới.

Và do đó, seqđầu ra của (là 20 dòng được đánh số liên tục) , sedchỉ in:

4
5
6
7
8
9
10
11
12
13

Điều này trở nên có vấn đề khi số lượng dòng bạn muốn tách khỏi phần đuôi của đầu vào là lớn - vì sedhiệu suất của nó tỷ lệ thuận với kích thước của không gian mẫu. Tuy nhiên, tuy nhiên, đây là một giải pháp khả thi trong nhiều trường hợp - và POSIX chỉ định một sedkhông gian mẫu để xử lý ít nhất 4kb trước khi phá sản.


1
gnu tailcũng hỗ trợ tail -n+<num>cú pháp mở rộng có nghĩa là "bắt đầu từ dòng <num>"
UloPe

4

Tôi sẽ không trả lời làm thế nào để xóa một số dòng. Tôi sẽ tấn công vấn đề theo cách này:

grep -v '#SQL>' Element_query >outfile

Thay vì đếm các dòng, nó loại bỏ các lệnh SQL bằng cách nhận ra các lời nhắc. Giải pháp này sau đó có thể được tổng quát hóa cho các tệp đầu ra khác của các phiên SQL với nhiều lệnh hơn chỉ hai.


Tôi thích nó. Tôi không biết nhiều về SQL - nhưng không có cơ hội nhắc nhở nào xảy ra ở đầu các dòng đầu ra của nó chứ?
mikeerv

4

edlà 'trình soạn thảo văn bản tiêu chuẩn' và nên có sẵn trên các hệ thống không có GNU sed. Ban đầu nó được thiết kế như một trình soạn thảo văn bản, nhưng nó rất phù hợp với kịch bản.

printf '%s\n' 1d '$d' w q | ed Element_query

1dxóa dòng đầu tiên của tệp, $d(trích dẫn để shell không nghĩ đó là biến) xóa dòng cuối cùng, wghi tệp và qthoát ed. printfở đây được sử dụng để định dạng các lệnh cho ed- mỗi lệnh được theo sau bởi một dòng mới; Tất nhiên có nhiều cách khác để thực hiện điều này.


3

Có một số cách để loại bỏ (các) dòng hàng đầu và cuối từ một tệp.

Bạn có thể sử dụng awkvì nó xử lý cả khớp mẫu và đếm dòng,

#you need to know length to skip last line, assume we have 100 lines
awk 'NR>1 && NR<100 {print $0};' < inputfile
#or
awk '/SQL/ {next}; {print $0;};' < inputfile |awk 'NR>1&& NR<10 {print $0};'

Bạn có thể sử dụng grep -vđể loại trừ các dòng bạn không muốn theo mẫu và bạn có thể khớp nhiều mẫu bằng -Etùy chọn này,

grep -v -E "SQL>" < inputfile > outputfile

Bạn có thể sử dụng headtailcắt bớt số lượng dòng cụ thể,

lines=$((`wc -l < inputfile`-2)) #how many lines in file, less 2
head -n-1 < inputfile | head -n$lines > outputfile
#or
tail -n+2 < inputfile | head -n$lines > outputfile

Bạn có thể sử dụng vi/vimvà xóa (các) dòng đầu tiên và cuối cùng,

vi inputfile
:1
dd
:$
dd
:w! outputfile
:x

bạn có thể sử dụng tập lệnh perl, bỏ qua dòng đầu tiên, lưu từng dòng, in khi bạn nhận được một dòng tiếp theo,

#left as exercise for the reader :-)

1
Đối với những người headbạn thực sự không cần đường ống, và trên thực tế, tốt hơn hết là không nên sử dụng nó nếu bạn có thể thoát khỏi nó. Khi bạn thực hiện head | head- trong khi hai quy trình có thể chạy đồng thời, cả hai đều xử lý thực tế tất cả các dữ liệu giống nhau. Nếu bạn làm thay vì { head >dump; head >save; } <inbạn chỉ bỏ qua bằng cách bù - dòng đầu tiên đọc 10 dòng ra >dumpvà dòng thứ hai đọc 10 dòng tiếp theo>save .
mikeerv

3

Bạn sẽ được phục vụ tốt hơn nhiều bằng cách cắt bỏ các lệnh SQL. Bạn có thể làm điều này theo hai cách:

  1. Nếu bạn hoàn toàn chắc chắn rằng chuỗi " SQL>" không xảy ra ở bất kỳ nơi nào khác trong đầu ra,

    grep -v -F 'SQL> ' < infile > outfile
  2. Nếu bạn không chắc chắn,

    grep -v '^SQL> .*;$' < infile > outfile

Phiên bản thứ hai chậm hơn nhưng chính xác hơn: nó sẽ bỏ qua các dòng chính xác bắt đầu bằng "SQL>" và kết thúc bằng dấu chấm phẩy, dường như mô tả các dòng bạn muốn loại bỏ.

Tuy nhiên, tốt hơn hết là không đặt đầu ra thêm đó vào tệp để bắt đầu. Hầu hết các hệ thống SQL có một số cách để làm điều đó. Tôi không nói quá nhiều với Oracle, nhưng có lẽ câu trả lời này có thể hữu ích.


3

Bạn có thể chọn các dòng giữa một phạm vi trong awk(điều này giả sử bạn biết có bao nhiêu dòng):

awk 'NR>1 && NR < 3' file

Hoặc trong Perl:

perl -ne 'print if $.>1 && $.<3' file

Nếu bạn không biết có bao nhiêu dòng, bạn có thể tính toán nó một cách nhanh chóng bằng cách sử dụng grep(lưu ý rằng điều này sẽ không tính các dòng trống, hãy sử dụng grep -c '' fileđể đếm chúng):

awk -vm="$(grep -c . file2.txt)" 'NR>1 && NR<m' file2.txt

3

Hãy thử giải pháp này:

tail -n +2 name_of_file | head -n-1

Tùy biến

Bạn có thể dễ dàng thích ứng với nó để xóa các dòng n đầu tiên thay đổi +2của tail;
hoặc để xóa các dòng n cuối cùng thay đổi -1của head.


Giải pháp này không chính xác vì nó in dòng đầu tiên.
xhienne

1
@xhienne Xin lỗi, đó là một sai lầm. Tôi đã viết 1 thay vì 2 là tham số của "đuôi". Bây giờ nó hoạt động, cảm ơn! :)
Gabrer

1

Sử dụng awk:

< inputfile awk 'NR>1 {print r}; {r=$0}' > outputfile
  • < inputfile: Chuyển hướng nội dung của inputfileđể awk'sstdin
  • > outputfile: Chuyển hướng nội dung của awk's stdoutđểoutputfile
  • NR>1: chỉ thực hiện các hành động sau nếu số lượng bản ghi đang được xử lý lớn hơn 1
  • {print r}: in nội dung của biến r
  • {r=$0}: gán nội dung của bản ghi đang được xử lý cho biến r

Vì vậy, ở lần thực thi đầu tiên của awktập lệnh, khối hành động đầu tiên không được thực thi, trong khi khối hành động thứ hai được thực thi và nội dung của bản ghi được gán cho biến r; ở lần thực hiện thứ hai, khối hành động đầu tiên được thực thi và nội dung của biến rđược in (do đó bản ghi trước được in); Điều này có tác dụng in từng dòng được xử lý nhưng dòng đầu tiên và dòng cuối cùng.


Bạn không loại trừ dòng đầu tiên. Tại NR == 2, bạn in dòng đầu tiên được lưu trữ trong r.
xhienne
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.