วิธีใช้ sed เพื่อลบบรรทัดสุดท้ายของไฟล์


148

ฉันต้องการที่จะลบบางnเส้นจากจุดสิ้นสุดของแฟ้ม สิ่งนี้สามารถทำได้โดยใช้ sed?

ตัวอย่างเช่นหากต้องการลบบรรทัดจาก 2 เป็น 4 ฉันสามารถใช้ได้

$ sed '2,4d' file

แต่ฉันไม่รู้หมายเลขบรรทัด ฉันสามารถลบบรรทัดสุดท้ายโดยใช้

$sed $d file

แต่ฉันต้องการทราบวิธีลบเส้นnจากจุดสิ้นสุด โปรดแจ้งให้ฉันทราบวิธีการใช้ sed หรือวิธีอื่น


2
@arashkordi: ที่ใช้นับบรรทัดจากด้านบนของไฟล์ไม่ใช่ด้านล่าง
ams

คำถามที่เกี่ยวข้องในsuperusers
Thor

//, อาจลองใช้การตั้งคำถามใหม่เพื่อให้เป็นเรื่องทั่วไปมากกว่าแค่ sed ?
Nathan Basanese

1
sed $d fileส่งคืนข้อผิดพลาด แต่ $ d ควรอยู่ในเครื่องหมายคำพูดเช่นนี้:sed '$d' file
Akronix

คำตอบ:


221

ฉันไม่รู้เกี่ยวกับsedแต่สามารถทำได้ด้วยhead:

head -n -2 myfile.txt

19
+1 เพื่อความง่าย คำสั่ง sed เทียบเท่าคือ butt ugly: sed -e :a -e '$d;N;2,5ba' -e 'P;D' file( ,5สำหรับ 5 บรรทัดสุดท้าย)
Marc B

62
โปรดทราบว่าสิ่งนี้ใช้ได้กับบางเวอร์ชันheadแต่ไม่ได้เป็นมาตรฐาน อันที่จริงมาตรฐานของheadรัฐ:The application shall ensure that the number option-argument is a positive decimal integer.
William Pursell

21
หากต้องการเพิ่มคำตอบของ @ WilliamPursell ... บนเชลล์เริ่มต้นของ Mac OS สิ่งนี้ไม่ทำงาน
JDS

7
หรือบน BSD แต่คำถามถูกติดแท็ก Linux
am

3
ลบ 1 เพราะนอกจาก osx นี่ใช้ไม่ได้กับ Ubuntu 14head: illegal line count -- -2
Michael Durrant

30

หาก hardcoding n เป็นตัวเลือกคุณสามารถใช้การโทรตามลำดับเพื่อกด ตัวอย่างเช่นหากต้องการลบสามบรรทัดสุดท้ายให้ลบหนึ่งบรรทัดสุดท้ายสามครั้ง:

sed '$d' file | sed '$d' | sed '$d'

2
สิ่งนี้บวกกับ -i เพื่อแก้ไขไฟล์แทนการทิ้งลงใน stdout ซึ่งทำงานให้ฉัน
WAF

27

จากสายซับหนึ่ง :

# delete the last 10 lines of a file
sed -e :a -e '$d;N;2,10ba' -e 'P;D'   # method 1
sed -n -e :a -e '1,10!{P;N;D;};N;ba'  # method 2

ดูเหมือนจะเป็นสิ่งที่คุณกำลังอยากได้


@Thor คุณสามารถเปลี่ยนจำนวนบรรทัดที่ถูกลบออกจากไฟล์โดยการเปลี่ยน10ใน'$d;N;2,10ba'
Alexej Magura

1
@AlexejMagura: ฉันแสดงความคิดเห็นกับคำตอบรุ่นก่อนหน้า
Thor

22

ตลกและเรียบง่ายsedและtacวิธีแก้ปัญหา:

n=4
tac file.txt | sed "1,$n{d}" | tac

บันทึก

  • "จำเป็นต้องใช้เครื่องหมายอัญประกาศคู่สำหรับเชลล์เพื่อประเมิน$nตัวแปรในsedคำสั่ง ในเครื่องหมายคำพูดเดี่ยวจะไม่มีการแก้ไข
  • tacเป็นสิ่งที่catตรงกันข้ามดูman 1 tac
  • {}ในsedจะมีการแยก$nและd(ถ้าไม่เปลือกพยายามที่จะอยู่ไม่ตีความ$ndตัวแปร)

7
fyi no tacบน osx
Michael Durrant

1
@MichaelDurrant port info coreutils|| brew info coreutils;
เสียง

19

ใช้sedแต่ให้เชลล์ทำการคำนวณด้วยเป้าหมายที่จะใช้dคำสั่งโดยกำหนดช่วง (เพื่อลบ 23 บรรทัดสุดท้าย):

sed -i "$(($(wc -l < file)-22)),\$d" file

หากต้องการลบ 3 บรรทัดสุดท้ายออกจากด้านใน:

$(wc -l < file)

กำหนดจำนวนบรรทัดของไฟล์: say 2196

เราต้องการลบ 23 บรรทัดสุดท้ายดังนั้นสำหรับด้านซ้ายหรือช่วง:

$((2196-22))

ให้: 2174 ดังนั้น sed ต้นฉบับหลังจากการตีความเปลือกคือ:

sed -i '2174,$d' file

เมื่อ-iทำการแก้ไขแบบ inplace ตอนนี้ไฟล์ก็เป็น2173บรรทัด!

หากคุณต้องการบันทึกลงในไฟล์ใหม่รหัสคือ:

sed -i '2174,$d' file > outputfile

15

คุณสามารถใช้หัวนี้

ใช้

$ head --lines=-N file > new_file

โดยที่ N คือจำนวนบรรทัดที่คุณต้องการลบออกจากไฟล์

เนื้อหาของไฟล์ต้นฉบับลบ N บรรทัดสุดท้ายอยู่ในnew_file


8

เพื่อความสมบูรณ์ฉันต้องการเพิ่มโซลูชันของฉัน ฉันลงเอยด้วยการทำสิ่งนี้กับมาตรฐานed:

ed -s sometextfile <<< $'-2,$d\nwq'

วิธีนี้จะลบ 2 บรรทัดสุดท้ายโดยใช้การแก้ไขในสถานที่ (แม้ว่าจะใช้ไฟล์ชั่วคราวใน/tmp!!)


5

ในการตัดไฟล์ที่มีขนาดใหญ่มากให้เข้าที่เรามีtruncateคำสั่ง ไม่ทราบเกี่ยวกับเส้น แต่tail+ wcสามารถแปลงบรรทัดเป็นไบต์:

file=bigone.log
lines=3
truncate -s -$(tail -$lines $file | wc -c) $file

มีสภาพการแข่งขันที่ชัดเจนหากไฟล์ถูกเขียนในเวลาเดียวกัน ในกรณีนี้อาจใช้งานได้ดีกว่าhead- นับจำนวนไบต์จากจุดเริ่มต้นของไฟล์ (mind disk IO) ดังนั้นเราจะตัดทอนขอบเขตของบรรทัดเสมอ (อาจเป็นบรรทัดมากกว่าที่คาดไว้หากไฟล์ถูกเขียนอย่างแข็งขัน):

truncate -s $(head -n -$lines $file | wc -c) $file

มีประโยชน์หนึ่งซับถ้าคุณล้มเหลวในการเข้าสู่ระบบพยายามใส่รหัสผ่านแทนชื่อผู้ใช้:

truncate -s $(head -n -5 /var/log/secure | wc -c) /var/log/secure

4

สิ่งนี้อาจใช้ได้กับคุณ (GNU sed):

sed ':a;$!N;1,4ba;P;$d;D' file

ดี คุณพลาดอะพอสโทรฟีตอนจบ ( ')
ธ อร์

ขออภัยสำหรับความคิดเห็นที่ล่าช้า แต่ฉันลองและ (adpated สำหรับ AIX / posix ของฉัน) มันล้มเหลวในการพิมพ์ทั้งหมดยกเว้นบรรทัดสุดท้าย การอ่านรหัสที่ฉันไม่เข้าใจว่าในช่วงสี่เส้นจะถูกลบออกห่วงอย่างชัดเจนคือเมื่อวันที่ 4 บรรทัดแรกจึงแน่นอนห่วงหลังจากd, DหรือPกับ GNU sed และไม่อยู่ในรุ่น POSIX เส้นดูเหมือนจะไม่ถูกพิมพ์หลังจากDและเก็บไว้ในบัฟเฟอร์การทำงานสำหรับลูปใหม่โดยไม่ผ่านไปยัง 'สิ้นสุด' ของบรรทัดการกระทำ
NeronLeVelu

@NeronLeVelu โปรแกรมอ่านในหน้าต่างของ 4 บรรทัดในพื้นที่รูปแบบแล้วผนวกบรรทัดถัดไปและพิมพ์บรรทัดแรกจนกว่ามันจะถึงจุดสิ้นสุดของไฟล์ที่มันจะลบบรรทัดที่เหลืออยู่
potong

@potong ใช่ฉันทดสอบกับ GNU sed และมันเก็บบัฟเฟอร์ระหว่างบรรทัดที่ posix ยกเลิกการโหลดหลังจากDสร้างเอฟเฟกต์ตรงกันข้าม
NeronLeVelu

4

คำตอบข้างต้นส่วนใหญ่ดูเหมือนจะต้องการคำสั่ง / ส่วนขยาย GNU:

    $ head -n -2 myfile.txt
    -2: Badly formed number

สำหรับวิธีแก้ปัญหาที่พกพาได้มากกว่า:

     perl -ne 'push(@fifo,$_);print shift(@fifo) if @fifo > 10;'

หรือ

     perl -ne 'push(@buf,$_);END{print @buf[0 ... $#buf-10]}'

หรือ

     awk '{buf[NR-1]=$0;}END{ for ( i=0; i < (NR-10); i++){ print buf[i];} }'

โดยที่ "10" คือ "n"


2

ด้วยคำตอบที่นี่คุณจะได้เรียนรู้แล้วว่า sed ไม่ใช่เครื่องมือที่ดีที่สุดสำหรับแอปพลิเคชันนี้

อย่างไรก็ตามฉันคิดว่ามีวิธีการทำเช่นนี้ในการใช้ sed; ความคิดคือการผนวก N บรรทัดเพื่อเก็บพื้นที่จนกว่าคุณจะสามารถอ่านได้โดยไม่ต้องกดปุ่ม EOF เมื่อ EOF ถูกตีให้พิมพ์เนื้อหาของพื้นที่พักและออก

sed -e '$!{N;N;N;N;N;N;H;}' -e x

คำสั่ง sed ด้านบนจะตัด 5 บรรทัดสุดท้าย


2

ลองคำสั่งต่อไปนี้:

n = line number
tail -r file_name | sed '1,nd' | tail -r

โปรดอธิบายวิธีการใช้งาน FYI - =เพื่อเริ่มต้นตัวแปรเปลือกเราไม่ควรจะมีพื้นที่รอบ ๆ
codeforester

@ codeforester บรรทัดแรกคือความคิดเห็นที่ฉันเดา เขาแค่ใช้สิ่งtail -rที่คนอื่นเคยใช้tacในการเรียงลำดับบรรทัดกลับและทำให้nบรรทัดสุดท้ายกลายเป็นnบรรทัดแรก
Nicolas Melay

2

สามารถทำได้ 3 ขั้นตอน:

a) นับจำนวนบรรทัดในไฟล์ที่คุณต้องการแก้ไข:

 n=`cat myfile |wc -l`

b) ลบจำนวนบรรทัดที่จะลบออกจากหมายเลขนั้น:

 x=$((n-3))

c) บอกให้กด sed เพื่อลบออกจากหมายเลขบรรทัดนั้น ( $x) ต่อท้าย:

 sed "$x,\$d" myfile

คณิตศาสตร์ไม่ดี หากคุณต้องลบ 3 บรรทัดจากนั้นลบ 3 แต่เพิ่ม 1 ด้วยคณิตศาสตร์ของคุณหากไฟล์มี 10 บรรทัด 10 - 3 = 7 และคุณใช้sedในการลบบรรทัด 7 ถึง 10 นั่นคือ 4 บรรทัดไม่ใช่ 3
mathguy

1

คุณสามารถรับจำนวนบรรทัดทั้งหมดด้วยwc -l <file>และใช้

head -n <total lines - lines to remove> <file>


1

การดำเนินการนี้จะลบ 3 บรรทัดสุดท้ายออกจากfile:

for i in $(seq 1 3); do sed -i '$d' file; done;


1
นี่เป็นวิธีที่แพงเกินไปสำหรับไฟล์ขนาดใหญ่ - ไฟล์ทั้งหมดจะต้องอ่านและเขียนซ้ำครั้ง! sedและส้อมเป็นจำนวนมากสำหรับ
codeforester

แม้ว่าวิธีนี้อาจไม่ใช่วิธีที่มีประสิทธิภาพที่สุด แต่ก็เป็นวิธีที่ตรงไปตรงมาและเข้าใจง่ายที่สุด
Dharam

0

ฉันชอบวิธีนี้

head -$(gcalctool -s $(cat file | wc -l)-N) file

โดยที่Nคือจำนวนบรรทัดที่จะลบ



0

หากต้องการลบ 4 บรรทัดสุดท้าย:

$ nl -b a file | sort -k1,1nr | sed '1, 4 d' | sort -k1,1n | sed 's/^ *[0-9]*\t//'   

ค่อนข้างหนัก (โดยเฉพาะในทรัพยากร) เปรียบเทียบกับหัว อย่างน้อยก็tac file | sed '1,4d' | tacเพราะการเรียงลำดับจากนั้นลบคำนำหน้า ressources ต้นทุนจำนวนมาก
NeronLeVelu

@NeronLeVelu คุณพูดถูก แต่ไม่มีtacคำสั่งบางระบบ (เช่น FreeBSD?)
mstafreshi

0

ฉันมากับสิ่งนี้โดยที่ n คือจำนวนบรรทัดที่คุณต้องการลบ:

count=`wc -l file`
lines=`expr "$count" - n`
head -n "$lines" file > temp.txt
mv temp.txt file
rm -f temp.txt

มันเป็นวงเวียนเล็ก ๆ น้อย ๆ แต่ฉันคิดว่ามันง่ายที่จะติดตาม

  1. นับจำนวนบรรทัดในไฟล์หลัก
  2. ลบจำนวนบรรทัดที่คุณต้องการลบออกจากการนับ
  3. พิมพ์จำนวนบรรทัดที่คุณต้องการเก็บและจัดเก็บในไฟล์ temp
  4. แทนที่ไฟล์หลักด้วยไฟล์ temp
  5. ลบไฟล์ temp

0

สำหรับการลบบรรทัด N สุดท้ายของไฟล์คุณสามารถใช้แนวคิดเดียวกันกับ

$ sed '2,4d' file

คุณสามารถใช้คอมโบพร้อมคำสั่ง tail เพื่อย้อนกลับไฟล์: ถ้า N คือ 5

$ tail -r file | sed '1,5d' file | tail -r > file

และวิธีนี้จะทำงานเช่นกันโดยที่head -n -5 fileคำสั่งไม่ทำงาน (เช่นบน mac!)


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