ฉันจะใช้ sed เพื่อลบบรรทัดทั้งหมดในไฟล์ข้อความที่มีสตริงที่ระบุได้อย่างไร
ฉันจะใช้ sed เพื่อลบบรรทัดทั้งหมดในไฟล์ข้อความที่มีสตริงที่ระบุได้อย่างไร
คำตอบ:
หากต้องการลบบรรทัดและพิมพ์เอาต์พุตไปที่มาตรฐาน:
sed '/pattern to match/d' ./infile
หากต้องการแก้ไขไฟล์โดยตรง - ใช้ไม่ได้กับ BSD sed:
sed -i '/pattern to match/d' ./infile
เหมือนกัน แต่สำหรับ BSD sed (Mac OS X และ FreeBSD) - ไม่ทำงานกับ GNU sed:
sed -i '' '/pattern to match/d' ./infile
หากต้องการแก้ไขไฟล์โดยตรง (และสร้างข้อมูลสำรอง) - ทำงานกับ BSD และ GNU sed:
sed -i.bak '/pattern to match/d' ./infile
sed '/pattern to match/d' ./infile > ./newfileหรือถ้าคุณต้องการที่จะทำแก้ไขในสถานที่แล้วคุณสามารถเพิ่ม-iธง sed sed -i '/pattern to match/d' ./infileในขณะที่ โปรดทราบว่าการ-iตั้งค่าสถานะต้องใช้ GNU sed และไม่สามารถพกพาได้
sed -i.backup '/pattern to match/d' ./infile) ที่ทำให้ฉันเจอกับการแก้ไขแบบแทนที่
sedไฟล์ที่ไม่ได้ควบคุมเวอร์ชัน
sed -i '' '/pattern/d' ./infileต้องโต้แย้งที่จะผ่านถึงแม้ว่ามันจะเป็นเพียงสตริงที่ว่างเปล่าเช่น
มีวิธีอื่น ๆ ในการลบบรรทัดด้วยสตริงที่ระบุนอกเหนือจากsed:
awk '!/pattern/' file > temp && mv temp file
ruby -i.bak -ne 'print if not /test/' file
perl -ni.bak -e "print unless /pattern/" file
while read -r line
do
[[ ! $line =~ pattern ]] && echo "$line"
done <file > o
mv o file
grep -v "pattern" file > temp && mv temp file
และแน่นอนsed(การพิมพ์ผกผันนั้นเร็วกว่าการลบจริง):
sed -n '/pattern/!p' file
sedตัวอย่างมีพฤติกรรมที่แตกต่างกันก็เพียง greps! sed -n -i '/pattern/!p' fileมันควรจะเป็นสิ่งที่ชอบ
grep -v "pattern" file > temp; mv temp fileสิ่งนี้อาจใช้กับตัวอย่างอื่น ๆ บางอย่างขึ้นอยู่กับค่าส่งคืน
seq -f %f 10000000 >foo.txt. sed d: time sed -i '' '/6543210/d' foo.txtจริง 0m9.294s sed! p: time sed -i '' -n '/6543210/!p' foo.txtจริง 0m13.671s (สำหรับไฟล์ขนาดเล็กความแตกต่างก็ใหญ่กว่า)
คุณสามารถใช้ sed เพื่อแทนที่บรรทัดในไฟล์ อย่างไรก็ตามดูเหมือนว่าจะช้ากว่าการใช้ grep มากสำหรับ inverse ไปเป็นไฟล์ที่สองแล้วย้ายไฟล์ที่สองไปที่ต้นฉบับ
เช่น
sed -i '/pattern/d' filename
หรือ
grep -v "pattern" filename > filename2; mv filename2 filename
คำสั่งแรกใช้เวลานานกว่าเครื่องของฉัน 3 เท่า
sed '/pattern/d' filename > filename2; mv filename2 filename
วิธีง่ายๆในการทำกับ GNU sed:
sed --in-place '/some string here/d' yourfile
-rตัวเลือก (หรือ-Eขึ้นอยู่กับรุ่นของคุณ) ซึ่งจะช่วยให้การใช้งานของ metacharacters regex ไม่+, ?, และ{...} (...)
คุณอาจพิจารณาใช้ex(ซึ่งเป็นตัวแก้ไขตามคำสั่ง Unix มาตรฐาน):
ex +g/match/d -cwq file
ที่อยู่:
+ดำเนินการให้คำสั่ง Ex ( man ex) เช่นเดียวกับ-cที่ดำเนินการwq(เขียนและออก)g/match/d- คำสั่ง Ex เพื่อลบบรรทัดที่กำหนดให้matchดู: Power of gตัวอย่างข้างต้นเป็นวิธีการที่สอดคล้องกับ POSIX สำหรับในสถานที่การแก้ไขไฟล์ตามนี้โพสต์ที่ Unix.SEและPOSIX exข้อกำหนดสำหรับ
ข้อแตกต่างsedคือ:
sedเป็นS Tream ED itor ไม่ใช่ตัวแก้ไขไฟล์ BashFAQ
หากคุณไม่ได้รับรหัสที่ไม่สามารถแปลได้โอเวอร์เฮดของ I / O และผลข้างเคียงอื่น ๆ ดังนั้นโดยทั่วไปพารามิเตอร์บางตัว (เช่นในตำแหน่ง / -i) เป็นส่วนขยาย FreeBSD ที่ไม่ได้มาตรฐานและอาจไม่สามารถใช้ได้กับระบบปฏิบัติการอื่น
man exทำให้คนvimนั้นดูเหมือนว่ามันexเป็นส่วนหนึ่งของกลุ่ม Vim ... ถ้าฉันเข้าใจถูกต้องนั่นหมายความว่ารูปแบบของไวยากรณ์matchคือvimregex.comซึ่งคล้ายกัน แต่แตกต่างจากรสชาติ POSIX และ PCRE หรือไม่
ฉันกำลังดิ้นรนกับสิ่งนี้ใน Mac นอกจากนี้ฉันต้องใช้การเปลี่ยนตัวแปร
ดังนั้นฉันจึงใช้:
sed -i '' "/$pattern/d" $file
โดยที่$fileเป็นไฟล์ที่ต้องการลบและ$patternเป็นรูปแบบที่จะจับคู่สำหรับการลบ
ฉันเลือก''จากความคิดเห็นนี้
สิ่งที่ต้องทราบที่นี่คือการใช้คำพูดสอง"/$pattern/d"ใน ตัวแปรจะไม่ทำงานเมื่อเราใช้เครื่องหมายคำพูดเดี่ยว
sedต้องการพารามิเตอร์หลังจาก-iนั้นดังนั้นหากคุณไม่ต้องการสำรองข้อมูลคุณยังต้องเพิ่มสตริงว่าง:-i ''
sed -i "/$pattern/d" $fileสำหรับการใช้เปลือก ขอบคุณสำหรับคำตอบ.
ฉันสร้างเกณฑ์มาตรฐานขนาดเล็กที่มีไฟล์ซึ่งมีประมาณ 345,000 บรรทัด วิธีที่grepดูเหมือนจะเร็วกว่าsedวิธีประมาณ 15 เท่าในกรณีนี้
ฉันลองทั้งโดยใช้และไม่มีการตั้งค่า LC_ALL = C ดูเหมือนว่าจะไม่เปลี่ยนการกำหนดเวลาอย่างมีนัยสำคัญ สตริงการค้นหา (CDGA_00004.pdbqt.gz.tar) อยู่ในตำแหน่งกึ่งกลางของไฟล์
นี่คือคำสั่งและเวลา:
time sed -i "/CDGA_00004.pdbqt.gz.tar/d" /tmp/input.txt
real 0m0.711s
user 0m0.179s
sys 0m0.530s
time perl -ni -e 'print unless /CDGA_00004.pdbqt.gz.tar/' /tmp/input.txt
real 0m0.105s
user 0m0.088s
sys 0m0.016s
time (grep -v CDGA_00004.pdbqt.gz.tar /tmp/input.txt > /tmp/input.tmp; mv /tmp/input.tmp /tmp/input.txt )
real 0m0.046s
user 0m0.014s
sys 0m0.019s
คุณยังสามารถใช้สิ่งนี้:
grep -v 'pattern' filename
ที่นี่-vจะพิมพ์เฉพาะที่นอกเหนือจากรูปแบบของคุณ (นั่นหมายถึงการสลับกลับกัน)
ในการรับผลลัพธ์แบบ inplace เช่นเดียวกับgrepคุณสามารถทำได้:
echo "$(grep -v "pattern" filename)" >filename
bashเชลล์หรือคล้ายกันเท่านั้น (ไม่ใช่tcsh)
perl -i -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3
คำสั่งแรกแก้ไขไฟล์ inplace (-i)
คำสั่งที่สองทำสิ่งเดียวกัน แต่เก็บสำเนาหรือสำรองข้อมูลของไฟล์ดั้งเดิมโดยเพิ่ม. bk ลงในชื่อไฟล์ (.bk สามารถเปลี่ยนเป็นอะไรก็ได้)
echo -e "/thing_to_delete\ndd\033:x\n" | vim file_to_edit.txt
ในกรณีที่มีคนต้องการทำเพื่อจับคู่สตริงคุณสามารถใช้การ-wตั้งค่าสถานะใน grep - w ทั้งหมด นั่นคือตัวอย่างเช่นถ้าคุณต้องการลบบรรทัดที่มีหมายเลข 11 แต่เก็บบรรทัดด้วยหมายเลข 111:
-bash-4.1$ head file
1
11
111
-bash-4.1$ grep -v "11" file
1
-bash-4.1$ grep -w -v "11" file
1
111
นอกจากนี้ยังทำงานร่วมกับการ-fตั้งค่าสถานะถ้าคุณต้องการที่จะแยกรูปแบบที่แน่นอนหลายรายการในครั้งเดียว หาก "บัญชีดำ" เป็นไฟล์ที่มีหลายรูปแบบในแต่ละบรรทัดที่คุณต้องการลบออกจาก "ไฟล์":
grep -w -v -f blacklist file
-w, --word-regexp Select only those lines containing matches that form whole words.vs.-x, --line-regexp Select only those matches that exactly match the whole line. For a regular expression pattern, this is like parenthesizing the pattern and then surrounding it with ^ and $.
cat filename | grep -v "pattern" > filename.1
mv filename.1 filename
เพื่อแสดงข้อความที่ได้รับการรักษาในคอนโซล
cat filename | sed '/text to remove/d'
เพื่อบันทึกข้อความที่ถือว่าเป็นไฟล์
cat filename | sed '/text to remove/d' > newfile
เพื่อผนวกข้อมูลข้อความที่ถือว่าเป็นไฟล์ที่มีอยู่
cat filename | sed '/text to remove/d' >> newfile
เพื่อจัดการกับข้อความที่ถือว่าอยู่แล้วในกรณีนี้ให้ลบบรรทัดที่ถูกลบออกไปมากขึ้น
cat filename | sed '/text to remove/d' | sed '/remove this too/d' | more
| moreจะแสดงข้อความในชิ้นหนึ่งหน้าในเวลา
คุณสามารถใช้ดีเก่าedที่จะแก้ไขไฟล์ในลักษณะคล้ายกับคำตอบexที่ใช้ ความแตกต่างที่สำคัญในกรณีนี้คือการedใช้คำสั่งผ่านอินพุตมาตรฐานไม่ใช่อาร์กิวเมนต์บรรทัดคำสั่งอย่างที่exสามารถทำได้ เมื่อใช้ในสคริปต์วิธีปกติในการรองรับสิ่งนี้คือการใช้printfไพพ์คำสั่ง:
printf "%s\n" "g/pattern/d" w | ed -s filename
หรือด้วย heredoc:
ed -s filename <<EOF
g/pattern/d
w
EOF