คำสั่ง sed ด้วยตัวเลือก -i ที่ล้มเหลวบน Mac แต่ทำงานบน Linux


303

ฉันใช้sedคำสั่งต่อไปนี้เพื่อค้นหา / แทนที่ข้อความใน Linux สำเร็จแล้ว:

sed -i 's/old_link/new_link/g' *

อย่างไรก็ตามเมื่อฉันลองบน Mac OS X ของฉันฉันจะได้รับ:

"คำสั่ง c คาดว่า \ ตามด้วยข้อความ"

ฉันคิดว่า Mac ของฉันใช้เชลล์ BASH แบบปกติ ว่าไง?

แก้ไข:

ตามประสิทธิภาพสูง @ นี่เป็นเพราะ Mac sedมีรสชาติที่แตกต่างกัน (BSD) ดังนั้นคำถามของฉันจะเป็นอย่างไรฉันจะทำซ้ำคำสั่งนี้ใน BSD ได้sedอย่างไร

แก้ไข:

นี่คือตัวอย่างจริงที่เป็นสาเหตุของสิ่งนี้:

sed -i 's/hello/gbye/g' *

1
ซึ่งหมายความว่าsedเห็น "c" ในข้อมูลของคุณเป็นคำสั่ง คุณใช้ตัวแปรหรือไม่? โปรดโพสต์สิ่งที่แสดงคำสั่งจริงและข้อมูลที่คุณกำลังประมวลผลอย่างใกล้ชิดยิ่งขึ้น echo x | sed cคุณจะได้รับการสาธิตที่เรียบง่ายของข้อผิดพลาดนี้โดยการทำ
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

@Dennis, คำสั่งง่ายๆข้างต้นทำให้เกิดสิ่งนี้แม้ว่าข้อมูลที่ประมวลผลจะเป็นเว็บไซต์ทั้งหมด (ฉันกำลังแปลงลิงก์รูปภาพทั้งหมด) รวมถึงไฟล์ html และ css ...
Yarin

คำตอบ:


397

หากคุณใช้ -iตัวเลือกที่คุณต้องการให้มีส่วนขยายสำหรับการสำรองข้อมูลของคุณ

ถ้าคุณมี:

File1.txt
File2.cfg

คำสั่ง (สังเกตการขาดช่องว่างระหว่าง-iและ''และ-eเพื่อทำให้ทำงานบน Mac เวอร์ชันใหม่และบน GNU):

sed -i'.original' -e 's/old_link/new_link/g' *

สร้างไฟล์สำรอง 2 ไฟล์เช่น:

File1.txt.original
File2.cfg.original

ไม่มีวิธีการพกพาที่จะหลีกเลี่ยงการทำไฟล์สำรองเพราะมันเป็นไปไม่ได้ที่จะหาคำสั่ง sed ที่ใช้งานได้ในทุกกรณี:

  • sed -i -e ...- ไม่ทำงานบน OS X เนื่องจากสร้าง-eข้อมูลสำรอง
  • sed -i'' -e ... - ไม่ทำงานบน OS X 10.6 แต่ใช้งานได้ตั้งแต่ 10.9+ ขึ้นไป
  • sed -i '' -e ... - ไม่ทำงานกับ GNU

บันทึกเนื่องจากว่าไม่มีคำสั่ง sed ทำงานบนทุกแพลตฟอร์มคุณสามารถลองใช้คำสั่งอื่นเพื่อให้ได้ผลลัพธ์เดียวกัน

เช่น, perl -i -pe's/old_link/new_link/g' *


4
ฉันมีปัญหาเดียวกัน ขอบคุณสำหรับการแก้ปัญหานี้ แต่ที่ฉันลองกับ 'man sed' เพื่อค้นหาคำอธิบายของ '-i' ไม่มีอะไรเกี่ยวกับการใช้ -i '' เพื่อละเว้นการสำรองข้อมูล นี่คือโทษแรกของฉัน ประการที่สองเมื่อข้อผิดพลาด "คำสั่งคาดว่า \ ตามด้วยข้อความ" ปรากฏขึ้นทำไมมันไม่บอกเราโดยตรงว่ามันต้องการชื่อสำรองสำหรับตัวเลือก '-i' !! ?? สิ่งนั้นเกิดขึ้นได้ทุกที่: คุณได้รับข้อผิดพลาด แต่ไม่ใช่สาเหตุของข้อผิดพลาดจากนั้นคุณค้นหาคู่มือที่อธิบายอะไรเกี่ยวกับมัน จากนั้นคุณ google เพื่อค้นหาคนอื่นก็มีปัญหาเดียวกัน ฉันหมายถึงทำไมไม่ให้ตัวอย่างในคู่มือ?
lukmac

หรือบอกเราว่าเหตุใดจึงเกิดข้อผิดพลาดแทนที่จะมีเพียงข้อความที่ไม่มีข้อมูลซึ่งมีข้อผิดพลาดเกิดขึ้น นี่เป็นข้อเสนอแนะสำหรับผู้ผลิตเครื่องมือทั้งหมดหากพวกเขาสามารถอ่านความคิดเห็นนี้ได้
lukmac

5
@ lukmac เท่าที่sedสามารถบอกได้คุณไม่ต้องใส่คำต่อท้ายการสำรองข้อมูล s/old_link/new_link/gคำต่อท้ายสำรอง อาร์กิวเมนต์ถัดไปหลังจากนั้นควรจะเป็นคำสั่งแก้ไข เนื่องจากมันตีความคำสั่งเป็นชื่อสำรองจึงใช้ชื่อไฟล์แรกเป็นคำสั่งแก้ไข แต่คำสั่งนั้นไม่ถูกต้อง
Barmar

2
สิ่งนี้จะเป็นปัญหาหรือไม่ มีวิธีใดบ้างที่ Apple อาจสามารถสร้างวิธีแก้ปัญหา / แพ็คเกจ GNU ที่ใช้ OSX ได้หรือไม่? หรือ GNU ไม่สามารถสนับสนุนได้sed -i '' -e ...ใช่ไหม
blong

5
sed -i'' -eดูเหมือนว่าจะไม่ทำงานตามที่คาดไว้ใน mac 10.14
MoOx


55

สิ่งนี้ใช้ได้กับ sed ทั้ง GNU และ BSD:

sed -i'' -e 's/old_link/new_link/g' *

หรือด้วยการสำรองข้อมูล:

sed -i'.bak' -e 's/old_link/new_link/g' *

หมายเหตุช่องว่างหลังจาก-iตัวเลือก! (จำเป็นสำหรับ GNU sed)


7
คนแรกที่ไม่ได้ทำงานใน OSX (ผมเคยทดสอบเพียงบน 10.6.8)
Marcin

4
สำหรับฉันใน OS X (10.10.3) ไฟล์แรกที่สร้างไฟล์สำรองจะต่อท้ายด้วย -e ไม่ดี. อย่างที่สองคือสิ่งเดียวที่ทำงานกับฉันอย่างสม่ำเสมอระหว่าง Ubuntu และ OS X ฉันไม่ต้องการไฟล์สำรองดังนั้นฉันจึงต้องเรียกใช้rmคำสั่งทันทีหลังจากลบ
เบรนแดน

1
บรรทัดแรกควรถูกเขียนใหม่ด้วยช่องว่างเพื่อทำงานใน 10.10: sed -i'' ...=>sed -i '' ...
Daniel Jomphe

3
@DanielJomphe แต่การเพิ่มพื้นที่นี้ไม่สามารถใช้กับ GNU sed ได้
Brice

1
@marcin อันแรกใช้ได้สำหรับฉันเช่นกันบน OSX 10.11.2 สิ่งเดียวคือมันสร้างไฟล์สำรองข้อมูลซึ่งจะต้องลบออกในภายหลัง ประการที่สองดูดีขึ้นเนื่องจากเราไม่ต้องคิดชื่อไฟล์ในภายหลัง
vikas027

41

พบปัญหาเดียวกันใน Mac และแก้ไขด้วยbrew:

brew install gnu-sed

และใช้เป็น

gsed SED_COMMAND

คุณสามารถตั้งค่ารวมทั้งตั้งsedชื่อแทนเป็นgsed(ถ้าคุณต้องการ):

alias sed=gsed

3
คุณไม่ให้ว่าทำไมคำตอบเดียวกันเป็นOhad Kravchick ?
gniourf_gniourf

1
การตั้งชื่อแทนเช่นนี้ไม่ใช่ความคิดที่ดี
SantaXL

1
แทนที่จะเป็นนามแฝงตามที่แนะนำในหน้าชงที่เกี่ยวข้องเพิ่มไปยังเส้นทาง: PATH = "$ (ชง - คำนำหน้า) / opt / gnu-sed / libexec / gnubin: $ PATH"
y.luis

24

หรือคุณสามารถติดตั้งรุ่น GNU ของ sed ใน Mac ของคุณที่เรียกว่า gsed และใช้งานได้โดยใช้ไวยากรณ์ Linux มาตรฐาน

เพื่อที่ติดตั้งgsedใช้พอร์ต (ถ้าคุณไม่ได้รับมันที่http://www.macports.org/ ) sudo port install gsedโดยการทำงาน จากนั้นคุณสามารถเรียกใช้sed -i 's/old_link/new_link/g' *


24
.. หรือถ้าคุณใช้ homebrew ให้ติดตั้งgnu-sed
Sudar

1
ขอบคุณ @Sudar ยกนิ้วให้!
Andrew Swan

9

Mac ของคุณใช้ BASH เชลล์จริง ๆ แต่นี่เป็นคำถามที่ว่าคุณต้องใช้อะไรบ้าง บน Mac sed มาจาก BSD และแตกต่างจาก sed อย่างละเอียดคุณอาจพบบนกล่อง Linux ทั่วไป man sedผมแนะนำให้คุณ


3
ขอบคุณสำหรับการชี้ให้เห็นปัญหา BSD - แต่ฉันค่อนข้างจะไม่รู้หนังสือและต้องการการแก้ไขอย่างรวดเร็วสำหรับคำสั่งของฉัน - การมองอย่างรวดเร็วที่ผู้ชายไม่ได้บอกอะไรฉันเลย
Yarin

5
@Yarin - ไม่และถ้าฉันมองไปที่ชายคนหนึ่งคุณก็ไม่ได้บอกอะไรคุณเลย ลองลองอีกครั้ง
เครื่องหมายประสิทธิภาพสูง

21
คำตอบ SO ส่วนใหญ่จะถูกฝังไว้ที่ใดที่หนึ่งในชายคนหนึ่ง แต่นั่นคือสิ่งที่ SO นั้นกำลังยุ่งอยู่กับคนที่ต้องการคำตอบจากคนฉลาด
Yarin

9

คำตอบของ Sinetris นั้นถูกต้อง แต่ฉันใช้สิ่งนี้พร้อมกับfindคำสั่งเพื่อเจาะจงเจาะจงมากขึ้นเกี่ยวกับไฟล์ที่ฉันต้องการเปลี่ยน โดยทั่วไปสิ่งนี้ควรใช้งานได้ (ทดสอบบน osx /bin/bash):

find . -name "*.smth" -exec sed -i '' 's/text1/text2/g' {} \;

โดยทั่วไปเมื่อใช้งาน sedโดยไม่มีfindโครงการที่ซับซ้อนจะมีประสิทธิภาพน้อยกว่า


-execดีมาก! ฉันแค่สงสัยว่าการเฉือนในตอนท้ายนั้นเป็นสิ่งที่จำเป็นจริงหรือ
เปล่า

2
@YeLiu โดยไม่มี\ผู้;ได้รับการตีความโดยเปลือกเมื่อฉันพยายามดังกล่าว
Serv-Inc

2

ฉันได้สร้างฟังก์ชันเพื่อจัดการsedความแตกต่างระหว่าง MacOS (ทดสอบบน MacOS 10.12) และระบบปฏิบัติการอื่น ๆ :

OS=`uname`
# $(replace_in_file pattern file)
function replace_in_file() {
    if [ "$OS" = 'Darwin' ]; then
        # for MacOS
        sed -i '' -e "$1" "$2"
    else
        # for Linux and Windows
        sed -i'' -e "$1" "$2"
    fi
}

การใช้งาน:

$(replace_in_file 's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"',' "./mysql/.env")

ที่ไหน:

, คือ delimeter

's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"',' เป็นรูปแบบ

"./mysql/.env" เป็นเส้นทางไปยังไฟล์


1

ต่อไปนี้เป็นวิธีใช้ตัวแปรสภาพแวดล้อมกับไฟล์เทมเพลต (ไม่จำเป็นต้องสำรองข้อมูล)

1. สร้างเทมเพลตด้วย {{FOO}} เพื่อทดแทนในภายหลัง

echo "Hello {{FOO}}" > foo.conf.tmpl

2. แทนที่ {{FOO}} ด้วยตัวแปร FOO และส่งออกไปยังไฟล์ foo.conf ใหม่

FOO="world" && sed -e "s/{{FOO}}/$FOO/g" foo.conf.tmpl > foo.conf

ทำงานได้ทั้งmacOS 10.12.4และUbuntu 14.04.5


0

ดังที่คำตอบอื่น ๆ ระบุไว้ไม่มีวิธีใดที่จะใช้พอร์ตแบบพกพาข้าม OS X และ Linux โดยไม่ต้องสร้างไฟล์สำรอง ดังนั้นฉันจึงใช้ Ruby one-liner นี้แทน:

ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml

ในกรณีของฉันฉันต้องเรียกมันจากrakeงาน (เช่นภายในสคริปต์ Ruby) ดังนั้นฉันจึงใช้การเพิ่มระดับของข้อความ:

sh %q{ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml}

-1
sed -ie 's/old_link/new_link/g' *

ทำงานได้ทั้งบน BSD และ Linux


3
สิ่งนี้สร้างใน linux ชื่อไฟล์อื่นที่มีeผนวก
Brice

1
เสียดีกว่าที่จะลบ
โซริน

มันทำงานบน Mac และ Linux ปัญหาในการแก้ไขปัญหานี้คืออะไร?
Islam Azab

ไม่มันไม่ทำงานบน Mac BSD Sed - มันจะสร้างไฟล์สำรองข้อมูลโดยเพิ่ม 'e' ในชื่อไฟล์
Jesper Grann Laursen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.