ฉันจะใช้ 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