วิธีทำการแทนที่แบบแทนที่ภายในที่สร้างเฉพาะการสำรองข้อมูลของไฟล์ที่เปลี่ยนแปลงไปแล้ว?


13

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

$ find . -type f -print0 | xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

สิ่งนี้ดำเนินการแทนที่คำ แต่ยังสร้าง.bupไฟล์ของไฟล์ที่ไม่เคยมีMs. Johnsonสตริง

ฉันจะทำการทดแทนโดยไม่สร้างการสำรองข้อมูลที่ไม่จำเป็นเหล่านี้ทั้งหมดได้อย่างไร


ดูเหมือนว่าฉันจะเป็นข้อบกพร่องของความเห็น
Hotschke

อาจเป็นวิธีที่ดีกว่าที่เป็นไปได้ในการใช้exและตามเงื่อนไข (เฉพาะในกรณีที่มีการเปลี่ยนแปลงไฟล์) ทำงาน:!cp '%' '%.bup'ก่อนที่จะบันทึกและออก อาจคุ้มค่าที่จะดู
Wildcard

ฉันเขียนคำถามเกี่ยวกับความคิดของฉันด้านบนในการviแลกเปลี่ยนสแต็ค
Wildcard

คำตอบ:


6

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

find . \
    -type f \
    -exec grep -q 'Ms. Johnson' {} \; \
    -print0 |
xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

หากคุณต้องการที่จะฉลาดจริง ๆ เกี่ยวกับเรื่องนี้คุณสามารถยกเลิกการใช้งานfindได้เลย:

grep -Z -l -r 'Ms. Johnson' |
    xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

1
ฉันคิดว่าคุณต้องมี'{}'ก่อนของคุณในการที่\; -exec
Jander

8

Find มีตัว-execดำเนินการที่ดำเนินการคำสั่งโดยพลการ ยิ่งไปกว่านั้น-execคือการทดสอบเพื่อให้คุณสามารถ-execโยงหลาย ๆ สายเข้าด้วยกันและหากคำสั่งก่อนหน้านี้ล้มเหลวคำสั่งต่อมาจะไม่ถูกเรียกใช้ สตริง{}จะถูกแทนที่ด้วยชื่อไฟล์ปัจจุบันและ;ทำเครื่องหมายจุดสิ้นสุดของคำสั่ง คุณควรอ้างอิงทั้งคู่เพื่อหลีกเลี่ยงการรบกวนของเชลล์

ดังนั้น:

find . -type f \
    -exec grep -q 'Ms. Johnson' '{}' \; \
    -exec sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g' '{}' \;

ฉันไม่เคยมีปัญหาในการใช้ {} ของเปล่า
แอมเฟตามาจิน

1
@amphetamachine: ฉันไม่มี แต่หน้าคนแนะนำมัน อาจเป็นสิ่ง csh หรืออาจมีเชลล์ (ไม่ใช่ Bash และไม่ใช่ POSIX) ที่ขยาย{}ไปยังสตริง null เมื่อทำการขยายรั้ง
Jander

4

ฉันดูหน้าคนและไม่เห็นวิธีที่จะทำโดยตรงผ่านsedฉันแน่ใจว่าคุณทำก่อนถาม ฉันเห็นหลายวิธีในการแก้ไขปัญหานี้โดยใช้ grep แต่ฉันคิดว่าวิธีที่ง่ายที่สุดคือ:

grep -rlZ "Ms. Johnson" . | xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

-rเรียกคืน
-lชื่อไฟล์พิมพ์เฉพาะ
-Zชื่อที่มีค่าว่างเท่านั้น


-1

ดูเหมือนว่าคุณจะต้องสร้างรายการไฟล์ที่ตรงกับคำค้นหาของคุณก่อน

search="test"
for match in $(find -type f -exec grep -l $search "{}" \;)
do sed -i'.bup' -e "/$search/ s/$search/Mrs. Melbin/g" "$match"
done

คุณลืมเป็นอาร์กิวเมนต์แรก. findนอกจากนี้ตามที่ฉันได้รับแจ้งตัวเองเมื่อไม่นานมานี้คุณไม่จำเป็นต้องอ้างหรือหลบหนี{}
Kevin

อย่าสร้างรายการไฟล์และทำการทดแทนคำสั่ง ขั้นแรกfindสร้างรายการไฟล์ที่คั่นด้วยบรรทัดใหม่จากนั้นเชลล์แยกรายการนี้ที่ช่องว่างใด ๆ (ไม่ใช่แค่บรรทัดใหม่) จากนั้นเชลล์จะถือว่าแต่ละคำเป็นรูปแบบกลม \[?*นี้จะทำงานเฉพาะถ้าชื่อไฟล์ของคุณไม่ได้มีช่องว่างหรือ คำตอบอื่น ๆ ในหน้านี้แสดงวิธีการทำอย่างถูกต้อง
Gilles 'หยุดความชั่วร้าย'

@Kevin The .ไม่จำเป็นต้องมี find (อย่างน้อย find find find บน linux) เพราะมันจะถูกสันนิษฐานว่าเมื่อไม่มีเส้นทางผ่านอาร์กิวเมนต์
laebshade
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.