ความแตกต่างระหว่าง sed บน Mac OSX และ sed“ มาตรฐาน” อื่น ๆ หรือไม่?


61

ฉันมีปัญหาบางอย่างในการใช้คำตอบที่ให้ไว้ในเว็บไซต์นี้สำหรับคำถามนี้เกี่ยวกับคำสั่ง sed เพื่อแทนที่บรรทัดว่างด้วยเนื้อหาอีกสองบรรทัดและมันก็เกิดขึ้นถ้าคำสั่ง sed บน Mac OS (10.6.7 สำหรับฉัน ) แตกต่างกัน ฉันไม่คิดว่ามันเป็น แต่สงสัยว่าคนอื่น ๆ ในเว็บไซต์นี้คิดแตกต่างกันหรือไม่

คำตอบ:


43

พฤติกรรมของยูทิลิตี้ของเชลล์จะแตกต่างกันในลักษณะที่แตกต่างกันเล็กน้อยระหว่างชุดยูนิกซ์ มีจำนวนมากยูนิกซ์สายพันธุ์ที่มีความซับซ้อน ประวัติศาสตร์ มีความพยายามมาตรฐานเช่นPOSIXมาตรฐานและเซ็ตของสเปคเดี่ยวยูนิกซ์ ระบบส่วนใหญ่ในปัจจุบันใช้ POSIX: 2001 หรือที่รู้จักในชื่อSingle UNIX Specification เวอร์ชั่น 3 ที่มีการเบี่ยงเบนเล็กน้อยและส่วนขยายจำนวนมาก ข้อมูลจำเพาะ Single Unix ไม่ใช่บทช่วยสอน แต่สามารถอ่านเวอร์ชัน 3 ได้หากคุณมีความคิดเกี่ยวกับสิ่งที่คำสั่งกำลังทำอยู่ คุณสามารถปรึกษาเพื่อทราบว่าคุณสมบัติบางอย่างเป็นมาตรฐานหรือเป็นส่วนขยายของระบบเฉพาะ

ผู้ใช้ระบบยูนิกซ์ส่วนใหญ่ใช้ Linux และไม่ได้ใช้ตัวแปรอื่นใด Linux มาพร้อมกับยูทิลิตี้GNUซึ่งมักจะมีส่วนขยายจำนวนมากตามมาตรฐาน ดังนั้นคุณจะพบรหัสจำนวนมากที่ทำงานบน Linux แต่ไม่ใช้กับ unices อื่น ๆ เพราะมันอาศัยส่วนขยายเหล่านั้น

เกี่ยวกับ sed ให้ศึกษาข้อมูลจำเพาะ sed Single Unixสำหรับขั้นต่ำที่ทุกระบบควรให้การสนับสนุนman page บนระบบของคุณสำหรับการใช้งานของคุณและGNU sed manualสำหรับสิ่งที่คนส่วนใหญ่ใช้อยู่

หนึ่งในส่วนขยายที่ไม่เป็นมาตรฐานใน GNU sed สนับสนุนการรันหลายคำสั่งพร้อมกัน ตัวอย่างเช่นโปรแกรม GNU sed พิมพ์บรรทัดทั้งหมดที่มีaแต่เปลี่ยนbเป็นบรรทัดcแรก:

sed -ne '/a/ {s/b/c/g; p}'

{และ}เป็นคำสั่งที่แยกต่างหากดังนั้นเพื่อความสะดวกในการพกพาคุณต้องระบุไว้ในบรรทัดที่แยกต่างหาก (ในไฟล์) หรือใน-eอาร์กิวเมนต์ที่แยกต่างหาก(บนบรรทัดคำสั่ง) การขาดตัวคั่นคำสั่งหลังจาก{และการใช้;เป็นตัวคั่นคำสั่งเป็นส่วนขยายทั่วไป การขาดตัวคั่นคำสั่งก่อนหน้า}นี้เป็นส่วนขยายที่น้อยกว่าทั่วไป นี่คือมาตรฐานที่เข้ากันได้:

sed -n -e '/a/ {' -e 's/b/c/g' -e p -e '}'

สิ่งนี้ไม่เป็นมาตรฐาน แต่ยอมรับกันโดยทั่วไป:

sed -ne '/a/ { s/b/c/g; p; }'

ส่วนขยายอื่นที่ไม่เป็นมาตรฐาน แต่ส่วนขยายทั่วไปคือการใช้\nเพื่อหมายถึงบรรทัดใหม่ในsข้อความแทนที่ (การใช้ใน regexp เป็นมาตรฐาน) วิธีการพกพาคือการรวมแบ็กสแลช - ขึ้นบรรทัดใหม่ในสคริปต์ sed อีกส่วนขยายที่พบบ่อยคือ\+, \?และ\|ใน regexps หมายถึงหนึ่งหรือมากกว่ามากที่สุดคนหนึ่งและสลับ; การแสดงออกปกติแบบพกพาขั้นพื้นฐานไม่มีสิ่งเหล่านี้ ตัวอย่างเช่นคำสั่งแรกเป็นวิธีที่ไม่ใช่แบบพกพาในการแทนที่ลำดับที่ต่อเนื่องกันของช่องว่างโดยขึ้นบรรทัดใหม่; คำสั่งที่สองนั้นเทียบเท่ามาตรฐาน

sed -e 's/ \+/\n/'
sed -e 's/  */\
/'

โปรดทราบว่าในทุกกรณีเกี่ยวกับส่วนขยายของ GNU นั่นคือการใช้งานที่ไม่ได้มาตรฐาน GNU sedเองนั้นเป็นไปตามมาตรฐานที่ได้รับอนุญาต มีหลายกรณีที่ไม่เข้ากันได้และที่ใช้งานPOSIXLY_CORRECTในสภาพแวดล้อมสามารถช่วยได้ เช่นเดียวกับs/[\n]//gที่จะต้องลบแบ็กสแลชและnตัวอักษร แต่ให้ลบบรรทัดใหม่แทน หรือพฤติกรรมของNคำสั่งในบรรทัดสุดท้าย
Stéphane Chazelas

sed -ne '/a/ { s/b/c/g; p; }'เป็นมาตรฐานตั้งแต่รุ่น 2016 ของมาตรฐาน มันพกพาได้เสมอ ดูaustingroupbugs.net/view.php?id=944&nbn=7
Stéphane Chazelas

60

ปัจจุบัน OS X มาพร้อมกับ FreeBSD sed จากปี 2005 ความแตกต่างด้านล่างส่วนใหญ่ยังใช้กับรุ่น BSD sed อื่น ๆ

OS X ของใช้ sed สำหรับการใช้งาน-E ERE และ GNU sed เป็นนามแฝงสำหรับใน GNU sed (เพิ่มใน 4.2 ไม่ได้บันทึกไว้จนถึง 4.3) รุ่นใหม่ของ FreeBSD และ NetBSD SED สนับสนุนทั้งและ OpenBSD sed สนับสนุนเท่านั้น-r-E-r-E-r-E

-i ''ทำงานร่วมกับ sed ของ OS X แต่ไม่ GNU sed -iทำงานร่วมกับ GNU sed, NetBSD รุ่นล่าสุด, OpenBSD sedแต่ไม่รวมถึง OS X -i -eทำงานได้กับทั้งสองอย่าง แต่ในกรณีของ FreeBSD sedทำให้การสำรองข้อมูลของไฟล์ต้นฉบับ-eต่อท้ายกับชื่อไฟล์ (และคุณต้องผ่านไม่เกินหนึ่งนิพจน์ไปsed)

GNU sed ตีความลำดับหนีเช่น\t, \n, \001, \x01, และ\w \bsed และ POSIX sed ของ OS X ตีความได้เฉพาะ\n(แต่ไม่ใช่ในส่วนการแทนที่s)

GNU sed ตีความ\|, \+และ\?ใน BRE แต่ OS X ของ sed และ POSIX sed ไม่ \(, \), \{และ\}มี POSIX BRE

GNU sed อนุญาตให้ข้าม;หรือขึ้นบรรทัดใหม่มาก่อน}แต่ sed ของ OS X ไม่ได้

i(insert), a(ผนวก) และc(เปลี่ยน) ต้องตามด้วยแบ็กสแลชและบรรทัดใหม่ใน sed ของ OS X และ POSIX sed แต่ไม่ใช่ใน GNU sed sed GNU เพิ่มขึ้นบรรทัดใหม่หายไปหลังจากที่ข้อความที่เขียนโดยi, aหรือcแต่ OS X ของ sed ไม่ ยกตัวอย่างเช่นsed 1iaเป็นทางเลือกที่ GNU sed $'1i\\\na\n'ไป

ตัวอย่างเช่นprintf a|sed -n pเพิ่มบรรทัดใหม่ใน sed ของ OS X แต่ไม่ได้อยู่ใน GNU sed

sed ของ OS X ไม่รองรับตัวดัดแปลงI(ตัวพิมพ์เล็ก - ใหญ่) หรือM(หลายบรรทัด) Iเวอร์ชั่นใหม่ของการสนับสนุน FreeBSD sed

sed ของ OS X ไม่รองรับ-s( --separate), -u( --unbuffered) หรือ-z( --null-data)

หนึ่งตัวเลือก BSD ที่ไม่รองรับโดย GNU sed คือ-aทำให้wผนวกไฟล์แทนการตัดทอนไฟล์

ตัวอย่างของคำสั่ง sed ของ GNU ที่ไม่ทำงานกับ sed ของ OS X:

sed /pattern/,+2d # like `sed '/pattern/{N;N;d;}'`
sed -n 0~3p # like `awk NR%3==0`
sed /pattern/Q # like `awk '/pattern/{exit}1'` or `sed -n '/pattern/,$!p'`
sed 's/\b./\u&/g' # \u converts the next character to uppercase
sed 's/^./\l&/' # \l converts the next character to lowercase
sed -i '1ecat file_to_prepend' file # e executes a shell command
sed -n l0 # 0 disables wrapping

4
-i -eไม่ทำงานบน OSX มัน interpets -eเป็นคำต่อท้าย
Chris Martin

3
@ChrisMartin ใช่ในเวอร์ชั่น OS X -iต้องใช้คำต่อท้ายเสมอแม้ว่าจะเป็นสตริงว่าง ดังนั้น-i '' -eควรทำงาน
waldyrious

@waldyrious ใช้งานได้กับ OSX เท่านั้น
Chris Martin

ใช่ว่าเป็นมุมแหลมของรุ่นที่ :)
waldyrious

3
ประโยค " -i -eใช้ได้กับทั้งคู่" ในคำตอบของคุณแนะนำว่ามีโซลูชันข้ามแพลตฟอร์ม เห็นได้ชัดว่าไม่มี
leondepeon

5

วิธีที่ดีที่สุดที่ฉันพบว่าการทำงานของสคริปต์เดียวกันบนทั้ง Linux และ Mac คือ:

sed -i.bak -e 's/foo/bar/' -- "${TARGET}" &&
  rm -- "${TARGET}.bak"

หรือใช้ในperlที่ที่-iมาจาก perl -Tpi -e 's/foo/bar/' -- "$TARGET"
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.