หากต้องการหาบรรทัดที่ถูกต้องลองเปลี่ยนเนื้อหาแล้วใส่กลับเข้าไปในไฟล์ต้นฉบับหรือไม่


9

ฉันพยายามที่จะเปลี่ยนคำเดียวในบรรทัดที่ระบุในไฟล์ แต่ฉันมีปัญหาในการเชื่อมต่อทั้งหมดเข้าด้วยกัน

โดยพื้นฐานแล้วในหนึ่งบรรทัดในไฟล์ของฉันมีคำสำคัญ 'firmware_revision' และในบรรทัดนี้ (และเฉพาะบรรทัดนี้) ฉันต้องการแทนที่คำว่า 'ทดสอบ' ด้วยคำว่า 'การผลิต'

ดังนั้นฉันสามารถทำสิ่งนี้:

grep 'firmware_revision' myfile.py | sed 's/test/production'

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

แม้ว่าฉันใช้ temporaries โดยใช้grepเพื่อรับสายฉันต้องฉันสูญเสียข้อมูลอื่น ๆ ในไฟล์ดังนั้นฉันไม่สามารถเพียงแค่เปลี่ยนมันทั้งหมดไปยังไฟล์ temp แล้วแทนที่เดิมด้วย temp

แก้ไข - มีคนถามข้อมูลเพิ่มเติม

ให้บอกว่าฉันมีไฟล์เต็มบรรทัดเช่นนี้

[
  ('key_name1', str, 'value1', 'Description'),
  ('key_name2', str, 'value2', 'Description'),
  ('key_name3', str, 'value3', 'Description'),
  ('firmware_revision', str, 'my-firmware-name-test', 'Firmware revision name')
]

ตอนนี้ฉันต้องการเขียนสคริปต์ (นึกคิดหนึ่งซับ) ที่จะหาบรรทัดที่มี 'firmware_revision' และเปลี่ยนอินสแตนซ์ทั้งหมดของคำว่า 'ทดสอบ' ในบรรทัดนั้นเป็น 'การผลิต' คำว่า 'test' อาจอยู่ที่อื่นในไฟล์นั้นและฉันไม่ต้องการให้เปลี่ยนแปลง เพื่อให้ชัดเจนฉันต้องการเปลี่ยนบรรทัดด้านบนเป็น

('firmware_revision', str, 'my-firmware-name-production', 'Firmware revision name')

ฉันจะทำสิ่งนี้ได้อย่างไร


5
sedมีประสิทธิภาพมากมันสามารถใช้งานได้ทั้งฟังก์ชั่น ( grepและการแทนที่) แต่เราต้องการข้อมูลเพิ่มเติมเกี่ยวกับลักษณะของสายเพื่อช่วยคุณ
grochmal

ฉันจะเพิ่มข้อมูลเพิ่มเติมในโพสต์ต้นฉบับ
John Allard

7
ลอง:sed -i.bak '/firmware_revision/ s/test/production/' myfile.py
John1024

1
อ่ามันทำงานได้อย่างสมบูรณ์แบบ! คุณช่วยอธิบายไวยากรณ์ได้ไหม?
John Allard

@ JohnAllard ดีมาก ฉันเพิ่มคำตอบพร้อมคำอธิบายแล้ว
John1024

คำตอบ:


22

ลอง:

sed -i.bak '/firmware_revision/ s/test/production/' myfile.py

ที่นี่/firmware_revision/ทำหน้าที่เป็นเงื่อนไข เป็นจริงสำหรับบรรทัดที่ตรงกับ regex firmware_revisionและ false สำหรับบรรทัดอื่น ๆ หากเงื่อนไขเป็นจริงคำสั่งที่ตามมาจะถูกดำเนินการ ในกรณีนี้คำสั่งที่เป็นคำสั่งที่ใช้แทนที่มาแทนที่เกิดขึ้นครั้งแรกของการมีtestproduction

ในคำอื่น ๆ คำสั่งs/test/production/จะถูกดำเนินการเฉพาะในสายซึ่งตรงกับ firmware_revisionregex บรรทัดอื่น ๆ ทั้งหมดผ่านไม่เปลี่ยนแปลง

โดยค่าเริ่มต้น sed ส่งออกไปยังมาตรฐานออก อย่างไรก็ตามคุณต้องการเปลี่ยนไฟล์ให้ถูกต้อง ดังนั้นเราจึงเพิ่ม-iตัวเลือก โดยเฉพาะอย่างยิ่ง-i.bakทำให้ไฟล์มีการเปลี่ยนแปลงพร้อมกับสำเนาสำรองที่บันทึกไว้พร้อมกับ.bakนามสกุล

หากคุณตัดสินใจว่าคำสั่งนั้นเหมาะกับคุณและคุณต้องการมีชีวิตที่เป็นอันตรายและไม่สร้างการสำรองข้อมูลจากนั้นด้วย GNU sed (Linux) ให้ใช้:

sed -i '/firmware_revision/ s/test/production/' myfile.py

ในทางตรงกันข้ามบน BSD (OSX) -iตัวเลือกจะต้องมีอาร์กิวเมนต์ หากคุณไม่ต้องการเก็บข้อมูลสำรองให้ระบุอาร์กิวเมนต์ว่างไว้ ดังนั้นการใช้:

sed -i '' '/firmware_revision/ s/test/production/' myfile.py

แก้ไข

ในการแก้ไขคำถามที่ OP ขอทุกการเกิดขึ้นของสายจะถูกแทนที่ด้วยtest productionในกรณีนั้นเราเพิ่มgตัวเลือกในคำสั่ง replace สำหรับการแทนที่แบบโกลบอล (สำหรับบรรทัดนั้น):

sed -i.bak '/firmware_revision/ s/test/production/g' myfile.py

5
เพื่อความสมบูรณ์คุณอาจต้องการอธิบาย-i.bakส่วนนี้ด้วย
Stephen Harris

5
@StephenHarris จุดที่ดี คำอธิบายของการ-iเพิ่ม
John1024

ฉันรู้สึกว่าคุณอาจจะถึงดวงดาวเพียงยืนอยู่บนหนังสือเล่มนี้อธิบายทุกสิ่งที่sedสามารถทำได้ ...
KlaymenDK

@ John1024 สำหรับไม่ BSD คนคุณสามารถเพิ่มเหตุผลของครั้งแรก ''หลังจากที่-i?
Hastur

3
OP ต้องการที่จะเปลี่ยนแปลงทุกกรณีของคำว่า 'ทดสอบ' ในบรรทัดที่ 'ผลิต' สิ่งสำคัญคือการผนวก / g ไปยังคำสั่ง sed ในกรณีนี้: sed -i '/firmware_revision/ s/test/production/g' myfile.pyมิฉะนั้นจะมีการเปลี่ยนแปลงอินสแตนซ์แรกเท่านั้น
knub

4

สำหรับเครื่องรุ่นเก่าที่มีรุ่นเก่าsedที่ไม่รองรับตัวเลือก-i:

TF=$( mktemp -t "${0##*/}"_$$_XXXXXXXX ) && \
trap 'rm -f "$TF"' EXIT HUP INT QUIT TERM && \
sed '/firmware_revision/ s/test/production/' myfile.py >"$TF" && \
mv -f "$TF" myfile.py

1
ในเครื่องรุ่นเก่าเหล่านั้นคุณสามารถใช้edและทำมันในหนึ่งบรรทัด:printf %s\\n g/firmware_revision/s/test/production/g w q | ed -s myfile.py
don_crissti

1
@don_crissti มากจริง แต่ed(1)ไม่ได้มีข้ออ้างใด ๆ mktemp(1)ที่จะแสดงให้เห็นการใช้งานของ
Satō Katsura

หากคุณกำลังใช้ tempfile คุณอาจรวมทั้งให้ inode และ perms ของไฟล์ต้นฉบับเช่นเดียวกับedไม่ แทนการใช้mv -f "$TF" myfile.pl cat "$TF" > myfile.pl && rm -f "$TF"BTW เป็นวิธีที่ดีที่จะใช้ชื่อตัวแปรตัวพิมพ์เล็ก ( $tfแทน$TF) พวกมันรับประกันว่าจะไม่ขัดแย้งกับ vash ในตัวของทุบตี (อาจเป็นเปลือก bourne อื่น ๆ ด้วย)
cas

@cas Re:: cat "$TF" > myfile.plลองสิ่งนี้: touch a b; chmod 0444 a; cat b >a(BTW, sed -iจะไม่ทำงานในกรณีนั้นเช่นกัน) ให้ผู้ใช้จัดการกับสิ่งนั้นดีกว่า Re: rm -f "$TF": trap ... EXITไม่จำเป็นต้องเห็น Re: $tfแทน$TF: อาจ; มันเป็นเรื่องของสไตล์
Satō Katsura

นั่นเป็นเรื่องปกติและพฤติกรรมที่คาดหวังของการอนุญาตให้ใช้ไฟล์ unix จุดของฉันคือการสร้างไฟล์ใหม่และ mv-ing มากกว่าความตั้งใจเดิม 1 ส่งผลให้ inode ใหม่สำหรับชื่อไฟล์นั้น (ทำลายฮาร์ดลิงก์ใด ๆ ) 2. อาจมีการเปลี่ยนแปลง perms หากปัจจุบันumask แตกต่างจาก perms เดิม สำหรับ vars ตัวพิมพ์ใหญ่มันไม่ใช่แค่เรื่องของสไตล์ - ผู้คนจำนวนมากที่ทำผิดพลาดในการใช้ PATH ตัวใหญ่หรือ RANDOM หรือ SHELL หรือตัวแปรของตัวเองได้ค้นพบวิธีที่ยาก (และใช่ฉันมักจะใช้ตัวพิมพ์ใหญ่ vars เองฉันรู้ว่ามันผิดฉันพยายามที่จะทำลายนิสัย)
cas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.