sed ทำงานแตกต่างกันใน FreeBSD และบน Linux?


12

ผมใช้ทั้ง Linux และ FreeBSD (โดยเฉพาะผมใช้ Debian Linux และ PC-BSD) sedและฉันพบบางสิ่งบางอย่างเกี่ยวกับแปลก

ฉันมักจะต้องแปลงไฟล์ "ค่าที่คั่นด้วยแท็บ" เป็น "ค่าที่คั่นด้วยเครื่องหมายจุลภาค" วิธีที่ง่ายที่สุดที่ฉันรู้คือใช้sedเช่นนี้

sed 's/\t/,/g' inputFile.txt > outputFile.csv

มันใช้งานได้ดีบน Linux: มันแทนที่ทุกแท็บด้วยเครื่องหมายจุลภาค ... แต่บน FreeBSD มันไม่ได้แทนที่อะไรเลย !!!

ฉันพลาดอะไรไปรึเปล่า? มีไวยากรณ์กับ FreeBSD sedที่แตกต่างจากหนึ่งบน Linux หรือไม่

คำตอบ:


9

บางทีคุณควรใช้-Eตัวเลือก (หรือ-rตามที่อธิบายไว้ในคู่มือ ) เพื่อให้เข้ากันได้กับ GNU Sed ในกรณีของคุณคุณสามารถติดตั้ง Gnu Sed หากคุณคุ้นเคย (พอร์ตgsedบน FreeBSD) หรือใช้ความพยายามอย่างยาวนานกับสคริปต์พอร์ต

และจำไว้ว่า. หากคำสั่งบางคำสั่งใน BSD ไม่ได้ทำหน้าที่เหมือนเวอร์ชัน gnu ของยูทิลิตีนั้นมันไม่ได้หมายความว่ามันพัง;)


1
ขอบคุณ. -Eตัวเลือกทำให้เคล็ดลับ (ทั้งใน FreeBSD และ Mac OS X)
Barranka

ใน FreeBSD 9 ของฉันตัวเลือก -E ไม่ได้ช่วยอะไร
Ark-kun

6

ใช่มีความแตกต่างหลากหลายพฤติกรรมของ-iการเป็นคนเดียวที่ฉันรู้จากด้านบนของหัวของฉัน

ฉันไม่เคยใช้ BSD ดังนั้นฉันจึงไม่สามารถช่วยรายละเอียดได้จริงๆ แต่วิธีแก้ปัญหาอาจใช้trแทน:

tr '\t' , < inputFile.txt > outputFile.csv

ผลข้างเคียงที่น่าพอใจก็คือtrควรจะเร็วขึ้นอย่างมีนัยสำคัญ ฉันทดสอบว่าบน Linux ของฉันโดยใช้ไฟล์ทดสอบที่มี 50,000 บรรทัดซึ่งแต่ละอันมี 2 แท็บ:

$ time tr '\t' , < foo.txt > /dev/null 

real    0m0.004s
user    0m0.000s
sys     0m0.000s

$ time sed 's/\t/,/g' foo.txt > /dev/null 

real    0m0.039s
user    0m0.036s
sys     0m0.000s

tr '\t' ,tr $'\t' ,เป็นแบบพกพามากกว่า tr '[\t]' '[,]'แม้จะพกพาไปยังระบบ SysV เก่า ๆ
Stéphane Chazelas

cutแท็บเป็นตัวคั่นเริ่มต้นสำหรับ ข้อมูลจำเพาะ POSIX สำหรับtrเป็นมี ฉันผิดเกี่ยวกับ[ความจำเป็นสำหรับ SysV เก่า เนื่องจาก POSIX นั้นมีจุด[เฉพาะสำหรับช่วงนั้น
Stéphane Chazelas

@ StephaneChazelas ดังนั้นมันคือขออภัยไม่แน่ใจว่าสิ่งที่ฉันสับสนด้วยแล้ว ขอบคุณสำหรับการชี้แจงในทุกกรณี
terdon

4

ใช่ต่างจาก GNU sedFreeBSD sedไม่ได้แปล ANSI C escape sequences เช่น\tในนิพจน์ทั่วไป

วิธีการหนึ่งที่จะได้รับ denomiator printfทั่วไปน้อยในกรณีนี้คือการใช้งาน

tab="$(printf '\t')"
printf '\t\n' | sed 's/'"${tab}"'/,/g'
printf '\t\n' | sed 's/'"$(printf '\t')"'/,/g'

พฤติกรรมของsed -iการแก้ไขไฟล์ในสถานที่สามารถทำให้เข้ากันได้หากสวิตช์หรือตัวเลือกถัดจากสวิตช์ทันที-iเช่นsed -i -e 's/x/X/g' fileทำงานได้ทั้ง GNU sedและ FreeBSDsed

รุ่นล่าสุดของ FreeBSD sed(FreeBSD 8.1 หรือใหม่กว่า) มี-rสวิทช์เพื่อเพิ่มความเข้ากันได้กับ sedGNU

(นอกจากนี้การใช้คลาสอักขระ POSIX ในsedนิพจน์ทั่วไปเป็นวิธีที่ดีในการตรวจสอบความเข้ากันได้เช่นกัน)

สำหรับทางเลือกที่ POSIX สอดคล้องsedการดำเนินการดู: minised - ขนาดเล็กราคาถูกกว่าการดำเนิน


3

คุณควรใช้ตัวTABอักษรแทน\t:

sed 's/    /,/g' inputFile.txt > outputFile.csv

ดูความคิดเห็นนี้โดย Stephane สำหรับคำถามอื่น

บทความต่อไปนี้อาจสนใจคุณ:

ฉันพูดส่วนที่เกี่ยวข้อง:

Regex Differences

ไวยากรณ์ของนิพจน์ทั่วไปแตกต่างกันอย่างละเอียดระหว่าง SED รุ่นต่างๆ ความแตกต่างส่วนใหญ่เกี่ยวข้องกับรูปแบบการหลบหลีกพิเศษที่ใช้เพื่อจับคู่อักขระที่ไม่พิมพ์เช่นระฆัง ASCI และฟีดฟอร์ม


0

หลังจากเข้าสู่ระบบฉันเห็นประกาศถัดไปและบันทึก หวังว่ามันจะมีประโยชน์สำหรับคนอื่นด้วย

ต้องการใช้ sed (1) เพื่อแก้ไขไฟล์หรือไม่ เมื่อต้องการแทนที่ 'e' ทุกตัวด้วย 'o' ในไฟล์ชื่อ 'foo' คุณสามารถทำได้:

sed -i.bak s/e/o/g foo

และคุณจะได้รับสำเนาสำรองของต้นฉบับในไฟล์ชื่อ 'foo.bak' แต่ถ้าคุณไม่ต้องการสำรองข้อมูล:

sed -i '' s/e/o/g foo

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