ฉันมีไฟล์foo.txt
,, มีบรรทัดต่อไปนี้:
a
b
c
ฉันต้องการคำสั่งง่ายๆที่ส่งผลให้เนื้อหาของfoo.txt
การเป็น:
a
b
ฉันมีไฟล์foo.txt
,, มีบรรทัดต่อไปนี้:
a
b
c
ฉันต้องการคำสั่งง่ายๆที่ส่งผลให้เนื้อหาของfoo.txt
การเป็น:
a
b
คำตอบ:
การใช้GNU sed
:
sed -i '$ d' foo.txt
-i
ตัวเลือกที่ไม่อยู่ในGNU sed
รุ่นเก่ากว่า 3.95 เพื่อให้คุณมีที่จะใช้เป็นตัวกรองด้วยไฟล์ชั่วคราว:
cp foo.txt foo.txt.tmp
sed '$ d' foo.txt.tmp > foo.txt
rm -f foo.txt.tmp
แน่นอนในกรณีที่คุณยังสามารถใช้แทนhead -n -1
sed
MacOS:
บน Mac OS X (จนถึง 10.7.4) เทียบเท่ากับsed -i
คำสั่งด้านบนคือ
sed -i '' -e '$ d' foo.txt
$ d
เป็น regex มันเป็นคำสั่ง sed d
คือคำสั่งสำหรับการลบบรรทัดในขณะที่$
หมายถึง "บรรทัดสุดท้ายในไฟล์" เมื่อระบุตำแหน่ง (เรียกว่า "ช่วง" ใน sed lingo) หน้าคำสั่งคำสั่งนั้นจะถูกนำไปใช้กับตำแหน่งที่ระบุเท่านั้น ดังนั้นคำสั่งนี้จะพูดว่า "ในช่วงของบรรทัดสุดท้ายในไฟล์ลบออก" ค่อนข้างเนียนและตรงประเด็นถ้าคุณถามฉัน
นี่เป็นวิธีที่เร็วและง่ายที่สุดโดยเฉพาะอย่างยิ่งในไฟล์ขนาดใหญ่:
head -n -1 foo.txt > temp.txt ; mv temp.txt foo.txt
ถ้าคุณต้องการที่จะลบบรรทัดด้านบนใช้สิ่งนี้:
tail -n +2 foo.txt
ซึ่งหมายความว่าบรรทัดเอาต์พุตเริ่มต้นที่บรรทัด 2
อย่าใช้sed
เพื่อลบบรรทัดจากด้านบนหรือด้านล่างของไฟล์ - มันช้ามากถ้าไฟล์มีขนาดใหญ่
head -n -1 foo.txt
เพียงพอแล้ว
brew install coreutils
(GNU สาธารณูปโภคหลัก) และใช้แทนghead
head
FILE=$1; TAIL=$2; head -n -${TAIL} ${FILE} > temp ; mv temp ${FILE}
เรียกใช้สำหรับการลบ 4 บรรทัดสำหรับตัวอย่างจาก myfile เป็น: ./TAILfixer myfile 4
แน่นอนทำให้มันปฏิบัติการโดยchmod +x TAILfixer
sed
คำสั่งนี้ค่อนข้างช้าเช่นกัน
ฉันมีปัญหากับคำตอบทั้งหมดที่นี่เพราะฉันทำงานกับไฟล์ขนาดใหญ่ (~ 300Gb) และไม่มีวิธีแก้ปัญหาใด ๆ นี่คือทางออกของฉัน:
dd if=/dev/null of=<filename> bs=1 seek=$(echo $(stat --format=%s <filename> ) - $( tail -n1 <filename> | wc -c) | bc )
ในคำ: ค้นหาความยาวของไฟล์ที่คุณต้องการท้ายด้วย (ความยาวของไฟล์ลบความยาวของบรรทัดสุดท้ายโดยใช้bc
) และกำหนดตำแหน่งนั้นให้เป็นจุดสิ้นสุดของไฟล์ (โดยใช้dd
หนึ่งไบต์ของ /dev/null
ลงบน มัน).
นี้เป็นไปอย่างรวดเร็วเพราะtail
การเริ่มต้นการอ่านจากสิ้นและdd
จะเขียนทับไฟล์ในสถานที่มากกว่าสำเนา (และแยก) บรรทัดของไฟล์ทุกซึ่งเป็นสิ่งที่โซลูชั่นอื่น ๆ ทำ
หมายเหตุ: นี่จะเป็นการลบบรรทัดออกจากไฟล์ในตำแหน่ง ทำสำเนาสำรองหรือทดสอบไฟล์ดัมมี่ก่อนลองใช้ไฟล์ของคุณเอง!
หากต้องการลบบรรทัดสุดท้ายออกจากไฟล์โดยไม่อ่านไฟล์ทั้งหมดหรือเขียนใหม่สิ่งใดคุณสามารถใช้
tail -n 1 "$file" | wc -c | xargs -I {} truncate "$file" -s -{}
หากต้องการลบบรรทัดสุดท้ายและพิมพ์ลงบน stdout ("pop") คุณสามารถรวมคำสั่งนั้นเข้ากับtee
:
tail -n 1 "$file" | tee >(wc -c | xargs -I {} truncate "$file" -s -{})
คำสั่งเหล่านี้สามารถประมวลผลไฟล์ที่มีขนาดใหญ่มากได้อย่างมีประสิทธิภาพ คำตอบนี้คล้ายกับและได้รับแรงบันดาลใจจาก Yossi แต่ก็หลีกเลี่ยงการใช้ฟังก์ชั่นพิเศษบางอย่าง
หากคุณจะใช้สิ่งเหล่านี้ซ้ำ ๆ และต้องการจัดการข้อผิดพลาดและคุณสมบัติอื่น ๆ คุณสามารถใช้poptail
คำสั่งได้ที่นี่:
https://github.com/donm/evenmoreutils
truncate
ไม่สามารถใช้ได้ใน OS X โดยค่าเริ่มต้น แต่มันเป็นเรื่องง่ายที่จะติดตั้งโดยใช้ brew install truncate
Brew:
ผู้ใช้ Mac
หากคุณต้องการเพียงแค่เอาท์พุทบรรทัดสุดท้ายที่ถูกลบโดยไม่เปลี่ยนไฟล์เอง
sed -e '$ d' foo.txt
หากคุณต้องการลบบรรทัดสุดท้ายของอินพุตไฟล์เอง
sed -i '' -e '$ d' foo.txt
-i ''
ล็กบอกให้ sed ปรับเปลี่ยนไฟล์แบบแทนที่ในขณะที่เก็บสำรองข้อมูลในไฟล์ที่มีนามสกุลที่ให้ไว้เป็นพารามิเตอร์ เนื่องจากพารามิเตอร์เป็นสตริงว่างไม่มีไฟล์สำรองถูกสร้างขึ้น -e
บอกให้ sed ดำเนินการคำสั่ง คำสั่ง$ d
หมายถึง: ค้นหาบรรทัดสุดท้าย ( $
) และลบมัน ( d
)
บน Mac หัว -n -1 ไม่ทำงาน และฉันพยายามหาวิธีแก้ปัญหาอย่างง่าย [โดยไม่ต้องกังวลเกี่ยวกับเวลาประมวลผล] เพื่อแก้ปัญหานี้โดยใช้คำสั่ง "head" และ / หรือ "tail" เท่านั้น
ฉันลองลำดับของคำสั่งต่อไปนี้และมีความสุขที่ฉันสามารถแก้มันได้โดยใช้คำสั่ง "tail" [พร้อมตัวเลือกที่มีใน Mac] ดังนั้นหากคุณใช้ Mac และต้องการใช้เฉพาะ "tail" เพื่อแก้ไขปัญหานี้คุณสามารถใช้คำสั่งนี้:
cat file.txt | tail -r | tail -n +2 | หาง -r
1> tail -r: กลับคำสั่งของเส้นในอินพุตของมัน
2> tail -n +2: นี่จะพิมพ์ทุกบรรทัดที่เริ่มต้นจากบรรทัดที่สองในการป้อนข้อมูล
ghead -n -1
echo -e '$d\nw\nq'| ed foo.txt
sed '$d'
สำหรับการแก้ปัญหาตัวกรองที่ไม่ได้แก้ไขไฟล์ในสถานที่ใช้งาน
awk 'NR>1{print buf}{buf = $0}'
เป็นหลักรหัสนี้บอกว่าต่อไปนี้:
สำหรับแต่ละบรรทัดหลังจากบรรทัดแรกพิมพ์บรรทัดที่บัฟเฟอร์
สำหรับแต่ละบรรทัดรีเซ็ตบัฟเฟอร์
บัฟเฟอร์มีความยาวหนึ่งบรรทัดดังนั้นคุณจึงพิมพ์บรรทัดที่ 1 ถึง n-1
awk "NR != `wc -l < text.file`" text.file |> text.file
ตัวอย่างนี้ทำเคล็ดลับ
โซลูชันทั้งสองนี้อยู่ในรูปแบบอื่น ฉันพบสิ่งเหล่านี้มีประโยชน์ชัดเจนและมีประโยชน์มากกว่านี้เล็กน้อย:
ใช้ dd:
BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
dd if=${ORIGINALFILE} of=${ORIGINALFILE}.tmp status=none bs=1 count=$(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc )
/bin/mv -f ${ORIGINALFILE}.tmp ${ORIGINALFILE}
ใช้ตัดทอน:
BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
truncate -s $(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc ) ${ORIGINALFILE}
sed '$d' ~/path/to/your/file/name
sed -i '' -e '$ d' ~/path/to/your/file/name
นี่เป็นวิธีที่คุณสามารถทำได้ด้วยตนเอง (ฉันใช้วิธีนี้บ่อยๆเมื่อฉันต้องการลบบรรทัดสุดท้ายในไฟล์):
vim + [FILE]
ว่า+
สัญญาณมีหมายความว่าเมื่อแฟ้มถูกเปิดในโปรแกรมแก้ไขข้อความที่เป็นกลุ่มเคอร์เซอร์จะถูกวางอยู่บนบรรทัดสุดท้ายของไฟล์
ตอนนี้เพียงแค่กด d
สองครั้งบนแป้นพิมพ์ของคุณ สิ่งนี้จะทำสิ่งที่คุณต้องการอย่างแน่นอน - ลบบรรทัดสุดท้าย หลังจากนั้นให้กด:
ตามมาด้วยและจากนั้นกดx
Enter
สิ่งนี้จะบันทึกการเปลี่ยนแปลงและนำคุณกลับไปที่เปลือก ตอนนี้ลบบรรทัดสุดท้ายเรียบร้อยแล้ว
ทับทิม (1.9+)
ruby -ne 'BEGIN{prv=""};print prv ; prv=$_;' file
sed -i
sed -i '' -e '$ d' foo.txt
นอกจากนี้head -n -1
จะไม่ทำงานบน Mac ในปัจจุบัน