ฉันจะลบบรรทัดแรกและบรรทัดสุดท้ายของไฟล์โดยใช้คำสั่งเชลล์ได้อย่างไร


31

ฉันมีไฟล์ชื่อElement_queryที่มีผลลัพธ์ของแบบสอบถาม:

SQL> select count (*) from element;

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

SQL> spool off;

ฉันต้องการลบบรรทัดที่ 1 และบรรทัดสุดท้ายโดยใช้คำสั่งเชลล์


2
คุณน่าจะแก้ไขได้ดีที่สุดใน SQL * Plus; แทนที่จะสร้างไฟล์แล้วพยายามตัดแต่งสิ่งที่คุณไม่ต้องการคุณสามารถบอก SQL * Plus ไม่ให้สร้างสิ่งนั้นเพื่อเริ่มต้นด้วย วิธีหนึ่งอธิบายไว้ในส่วน "การสร้างไฟล์แฟลต" ที่docs.oracle.com/cd/A84870_01/doc/sqlplus.816/a75664/ch44.htm ; อีกวิธีหนึ่งคือการอธิบายที่stackoverflow.com/q/2299375/978917
ruakh

คำตอบ:


48

ใช้ GNU sed:

sed -i '1d;$d' Element_query

มันทำงานอย่างไร :

  • -iตัวเลือกแก้ไขไฟล์ของตัวเอง คุณสามารถลบตัวเลือกนั้นและเปลี่ยนเส้นทางผลลัพธ์ไปยังไฟล์ใหม่หรือคำสั่งอื่นหากคุณต้องการ
  • 1dลบบรรทัดแรก ( 1เพื่อดำเนินการในบรรทัดแรกเท่านั้นdเพื่อลบ)
  • $dลบบรรทัดสุดท้าย ( $เพื่อดำเนินการกับบรรทัดสุดท้ายเท่านั้นdเพื่อลบ)

ไปเพิ่มเติม:

  • คุณยังสามารถลบช่วงได้ ตัวอย่างเช่น1,5dจะลบ 5 บรรทัดแรก
  • คุณสามารถลบทุกบรรทัดที่ขึ้นต้นด้วยการSQL>ใช้คำสั่ง/^SQL> /d
  • คุณสามารถลบทุกบรรทัดว่างด้วย /^$/d
  • ในที่สุดคุณสามารถรวมคำสั่งใด ๆ โดยแยกพวกเขาด้วยเซมิโคลอน ( statement1;statement2;satement3;...) หรือโดยการระบุแยกต่างหากในบรรทัดคำสั่ง ( -e 'statement1' -e 'statement 2' ...)

ถ้าบรรทัดที่ 3 ลบ ... แล้วฉันต้องใช้ 3d แทน 1d หรือไม่ ถ้าบรรทัดที่ 3 จากครั้งสุดท้ายที่จะลบ ... แล้วสิ่งที่จะเป็นคำสั่ง?
pmaipmui

วิธีการลบบรรทัดที่ 3 จากคำสั่งสุดท้ายโดยใช้คำสั่งเชลล์?
pmaipmui

@Nainita คุณสามารถระบุช่วง ( 1,3dจะลบสามบรรทัดแรก) แต่มันยากขึ้นเล็กน้อยในตอนท้าย ขึ้นอยู่กับสิ่งที่คุณต้องการคุณควรใช้สิ่งนี้ดีกว่า: sed -i '/^SQL> /d' Element_queryเพื่อลบบรรทัดที่ขึ้นต้นด้วยSQL> ไม่ว่าจะอยู่ที่ไหนในไฟล์
user43791

@ Nainita - ดูคำตอบของฉันที่นี่เพื่อนับหางโดยพลการ - มันมีสองโซลูชั่นสำหรับการลอกเส้นนับเมื่อเทียบกับจุดสิ้นสุดของไฟล์ หนึ่งคือsedหนึ่งซับ - ซึ่งจะทำงานสำหรับการปอกสายโดยพลการนับจากหัวและส่วนท้ายของไฟล์ที่ดีกว่าแม้ว่าตราบใดที่อินพุตเป็นไฟล์ปกติเป็นเพียงการจัดกลุ่มอินพุตเดียวในสองheadกระบวนการ - มันเป็น วิธีที่เร็วที่สุดในการทำเช่นนี้มักจะ
mikeserv

ฉันเคยsed -i '1d' table-backup.sqlลบบรรทัดแรกของไฟล์ข้อความ sql
David Thomas

8

หัว; หัว

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

ด้วยข้างต้นคุณสามารถระบุจำนวนบรรทัดแรกที่จะตัดออกจากส่วนหัวของเอาต์พุตที่มีheadคำสั่งแรกและจำนวนบรรทัดที่จะเขียนoutfileด้วยที่สอง โดยทั่วไปแล้วจะทำสิ่งนี้เร็วกว่าsed- โดยเฉพาะเมื่ออินพุตมีขนาดใหญ่ - แม้ว่าจะต้องการการเรียกใช้สองครั้ง ที่ไหนsedแน่นอนควรเป็นที่ต้องการ แต่เป็นในกรณีที่<infileเป็นไม่ปกติlseekableไฟล์ - เพราะนี้จะมักจะไม่ได้ทำงานตามที่ตั้งใจไว้ในกรณีที่ว่า แต่sedสามารถจัดการกับการปรับเปลี่ยนการส่งออกทั้งหมดในกระบวนการเดียวสคริปต์

ด้วย GNU headคุณสามารถใช้-รูปแบบเชิงลบ[num]ในคำสั่งที่สองได้เช่นกัน ในกรณีนี้คำสั่งต่อไปนี้จะตัดบรรทัดแรกและบรรทัดสุดท้ายจากอินพุต:

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

หรือด้วย POSIX sed:

ตัวอย่างเช่นฉันกำลังอ่านอินพุต 20 บรรทัดและฉันต้องการตัด 3 ตัวแรกและ 7 ตัวสุดท้ายถ้าฉันตัดสินใจที่จะทำเช่นนั้นด้วย / sedฉันจะทำด้วยหางบัฟเฟอร์ ฉันจะรวมสามและเจ็ดเข้าด้วยกันเพื่อนับจำนวนสตริปสิบแล้วทำ:

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

นั่นคือตัวอย่างที่แยก 3 และ 7 บรรทัดแรกจากอินพุต แนวคิดคือคุณสามารถบัฟเฟอร์ได้หลายบรรทัดตามที่คุณต้องการตัดจากส่วนท้ายของอินพุตในพื้นที่รูปแบบบนสแต็ก แต่ใช้เพียงPบรรทัดแรกของบรรทัดเหล่านี้สำหรับทุกบรรทัดที่ดึงเข้าไป

  • ในบรรทัด1,10 sed Prints ไม่มีอะไรเพราะสำหรับแต่ละเหล่านั้นมันเป็นสแต็คอินพุทในช่องว่างรูปแบบบรรทัดต่อบรรทัดในbลูปฟาร์มปศุสัตว์
  • ในบรรทัดที่ 3 sedสแต็กทั้งหมดจะถูกdลบ - และเพื่อให้ 3 บรรทัดแรกถูกถอดออกจากเอาต์พุตในการปัดทิ้งหนึ่งครั้ง
  • เมื่อมาsedถึง$บรรทัดสุดท้ายของอินพุตและพยายามดึงเข้าไปในส่วนขยายNมันจะกระทบ EOF และหยุดการประมวลผลทั้งหมด แต่ในเวลานั้นพื้นที่รูปแบบนั้นมีทุกบรรทัด14,20- ไม่มีสิ่งใดที่ถูกPrinted และไม่เคยเป็น
  • ในทุก ๆ บรรทัดอื่น ๆ จะsed Pเรียกใช้เฉพาะ ewline แรกที่เกิดขึ้น\nในพื้นที่รูปแบบเท่านั้นและจะDลบเหมือนเดิมก่อนที่จะเริ่มรอบใหม่ด้วยสิ่งที่เหลืออยู่ - หรืออินพุต 6 บรรทัดถัดไป บรรทัดที่ 7 ถูกต่อท้ายอีกครั้งกับสแต็กด้วยNคำสั่ง ext ในรอบใหม่

และเพื่อให้การseqของเอาท์พุท(ซึ่งเป็น 20 หมายเลขตามลำดับเส้น) , sedเพียงพิมพ์:

4
5
6
7
8
9
10
11
12
13

สิ่งนี้จะเป็นปัญหาเมื่อจำนวนบรรทัดที่คุณต้องการตัดออกจากส่วนท้ายของอินพุตมีขนาดใหญ่เนื่องจากsedประสิทธิภาพของมันจะแปรผันตรงกับขนาดของพื้นที่รูปแบบ แต่ถึงกระนั้นมันก็เป็นทางออกที่ทำงานได้ในหลายกรณี - และ POSIX ระบุsedพื้นที่รูปแบบที่จะจัดการอย่างน้อย 4kb ก่อนที่จะหยุด


1
gnu tailยังรองรับtail -n+<num>ความหมายของไวยากรณ์เพิ่มเติม"เริ่มจากบรรทัด<num>"
UloPe

4

ฉันจะไม่ตอบวิธีลบจำนวนบรรทัด ฉันจะโจมตีปัญหาด้วยวิธีนี้:

grep -v '#SQL>' Element_query >outfile

แทนที่จะนับบรรทัดมันจะกำจัดคำสั่ง SQL ด้วยการจดจำพร้อมต์ วิธีแก้ปัญหานี้สามารถทำให้เป็นมาตรฐานสำหรับไฟล์เอาต์พุตอื่นของเซสชัน SQL ที่มีคำสั่งมากกว่าสองไฟล์


ฉันชอบมัน. ฉันไม่รู้ SQL มาก - แต่มีโอกาสที่จะเกิดขึ้นที่ส่วนหัวของบรรทัดเอาท์พุทหรือไม่?
mikeserv

4

edคือ 'แก้ไขข้อความมาตรฐานและควรจะมีอยู่ในระบบที่ไม่ได้มี sedGNU เดิมทีถูกออกแบบมาเป็นโปรแกรมแก้ไขข้อความ แต่มันก็เหมาะสมกับการเขียนสคริปต์

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

1dลบบรรทัดแรกของไฟล์$d(อ้างเพื่อให้เปลือกไม่คิดว่ามันเป็นตัวแปร) ลบบรรทัดสุดท้ายwเขียนไฟล์และลาออกq ใช้ที่นี่เพื่อจัดรูปแบบคำสั่งสำหรับ- แต่ละอันจะต้องตามด้วยการขึ้นบรรทัดใหม่ มีวิธีอื่นที่จะทำให้สำเร็จedprintfed


3

มีหลายวิธีในการลบบรรทัดนำหน้าและส่วนท้ายออกจากไฟล์

คุณสามารถใช้awkเนื่องจากมันรองรับทั้งการจับคู่รูปแบบและการนับบรรทัด

#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};'

คุณสามารถใช้grep -vเพื่อแยกบรรทัดที่คุณไม่ต้องการตามรูปแบบและคุณสามารถจับคู่หลายรูปแบบโดยใช้-Eตัวเลือก

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

คุณสามารถใช้headและtailตัดจำนวนเส้นที่ระบุ

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

คุณสามารถใช้vi/vimและลบบรรทัดแรกและบรรทัดสุดท้ายได้

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

คุณสามารถใช้สคริปต์ Perl ข้ามบรรทัดแรกบันทึกแต่ละบรรทัดพิมพ์เมื่อคุณได้รับบรรทัดถัดไป

#left as exercise for the reader :-)

1
สำหรับสิ่งheadที่คุณไม่จำเป็นต้องใช้ในท่อและในความเป็นจริงมันจะดีกว่าที่จะไม่ใช้เลยถ้าคุณสามารถหนีไปได้ เมื่อคุณทำhead | head- ในขณะที่กระบวนการทั้งสองสามารถทำงานพร้อมกันพวกเขาทั้งสองก็กำลังประมวลผลข้อมูลเดียวกันทั้งหมดในทางปฏิบัติซ้ำซ้อน ถ้าคุณทำแทน{ head >dump; head >save; } <inคุณจะข้ามโดยชดเชย - ครั้งแรกที่อ่าน 10 บรรทัดออกไป>dumpและครั้งที่สองอ่านต่อไป 10 >saveเส้นออกไป
mikeserv

3

คุณจะได้รับบริการที่ดียิ่งขึ้นโดยการตัดคำสั่ง SQL ออกไป คุณสามารถทำได้สองวิธี:

  1. ถ้าคุณแน่ใจอย่างแน่นอนว่าลำดับ " SQL>" จะไม่เกิดขึ้นที่ใดก็ตามในเอาต์พุต

    grep -v -F 'SQL> ' < infile > outfile
  2. หากคุณไม่แน่ใจ

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

รุ่นที่สองช้ากว่า แต่มีความแม่นยำมากกว่า: จะละเว้นบรรทัดที่ขึ้นต้นด้วย "SQL>" และลงท้ายด้วยเครื่องหมายอัฒภาคซึ่งดูเหมือนจะอธิบายบรรทัดที่คุณต้องการตัดออก

อย่างไรก็ตามจะเป็นการดีกว่าถ้าไม่ให้ใส่เอาต์พุตพิเศษนั้นในไฟล์เพื่อเริ่มต้น ระบบ SQL ส่วนใหญ่มีวิธีการทำเช่นนั้น ฉันไม่ได้คุ้นเคยกับ Oracle มากนัก แต่คำตอบนี้อาจมีประโยชน์


3

คุณสามารถเลือกบรรทัดระหว่างช่วงawk(สมมติว่าคุณรู้ว่ามีกี่บรรทัด):

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

หรือในภาษา Perl:

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

หากคุณไม่ทราบว่ามีกี่บรรทัดคุณสามารถคำนวณได้ทันทีโดยใช้grep(โปรดทราบว่านี่จะไม่นับบรรทัดว่างให้ใช้grep -c '' fileเพื่อนับพวกเขาเช่นกัน):

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

3

ลองวิธีนี้:

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

การปรับแต่ง

คุณสามารถปรับเปลี่ยนได้อย่างง่ายดายเพื่อลบ n บรรทัดแรกที่เปลี่ยน+2ของtail;
หรือลบเส้น n ที่ผ่านมาการเปลี่ยนแปลงของ-1head


วิธีนี้ไม่ถูกต้องเนื่องจากจะพิมพ์บรรทัดแรก
xhienne

1
@xhienne ขออภัยมันเป็นความผิดพลาด ฉันเขียน 1 แทน 2 เป็นพารามิเตอร์ของ "tail" ตอนนี้ได้ผลขอบคุณ! :)
Gabrer

1

การใช้awk:

< inputfile awk 'NR>1 {print r}; {r=$0}' > outputfile
  • < inputfile: เปลี่ยนเส้นทางเนื้อหาของinputfileไปawkที่stdin
  • > outputfile: เปลี่ยนเส้นทางเนื้อหาของawk's stdoutไปoutputfile
  • NR>1: ดำเนินการกระทำต่อไปนี้เฉพาะในกรณีที่จำนวนของระเบียนที่กำลังดำเนินการมากกว่า 1
  • {print r}: พิมพ์เนื้อหาของตัวแปร r
  • {r=$0}: กำหนดเนื้อหาของบันทึกที่กำลังดำเนินการกับตัวแปร r

ดังนั้นในการดำเนินการครั้งแรกของawkสคริปต์บล็อกแรกของการกระทำที่ไม่ได้ดำเนินการในขณะที่บล็อกที่สองของการกระทำจะถูกดำเนินการและเนื้อหาของบันทึกที่ได้รับมอบหมายให้กับตัวแปรr; ในการดำเนินการครั้งที่สองจะมีการดำเนินการบล็อกแรกของการดำเนินการและเนื้อหาของตัวแปรrจะถูกพิมพ์ (เพื่อบันทึกก่อนหน้านี้จะถูกพิมพ์); สิ่งนี้มีผลกระทบของการพิมพ์แต่ละบรรทัดที่ประมวลผล แต่บรรทัดแรกและบรรทัดสุดท้าย


คุณไม่ได้ยกเว้นบรรทัดแรก ที่ NR == 2 rคุณพิมพ์บรรทัดแรกของการป้อนข้อมูลที่เก็บไว้ใน
xhienne
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.