การค้นหาเสียงเรียกเข้าแทนที่ไฟล์ทั้งหมดในโฟลเดอร์ปัจจุบัน (โครงการ)


36

หนึ่งในคำถามเปิดที่ฉันมีเกี่ยวกับ Vim คือถ้ามีวิธีทำการค้นหา / แทนที่ในโครงการปัจจุบัน (อดทนกับฉันหากฉันใช้ความคิดนี้ที่สืบทอดมาจากบรรณาธิการอื่น ๆ )

ตัวอย่างเช่นสมมติว่าฉันต้องการค้นหาชื่อไฟล์โครงการของฉันและเปลี่ยนชื่ออินสแตนซ์ทั้งหมดของการเรียกใช้เมธอดนั้น

นี่คือวิธีที่ฉันสามารถดำเนินการกับประเสริฐ

ป้อนคำอธิบายรูปภาพที่นี่

วิธีที่คุณจะทำเช่นนี้ในกลุ่ม (อาจ MacVim) โดยไม่ต้องอาศัยโปรแกรมอื่น ๆ เช่นackหรือsed?

คำตอบ:


35

มีหลายวิธีในการทำเช่นนี้

ภายในไดเรกทอรีปัจจุบัน

หากคุณต้องการที่จะดำเนินการค้นหา / แทนที่ในต้นไม้โครงการ, คุณสามารถใช้เป็นกลุ่มของรายการอาร์กิวเมนต์

เพียงเปิด Vim จากนั้นใช้:argsคำสั่งเพื่อเติมรายการอาร์กิวเมนต์ คุณสามารถผ่านชื่อไฟล์หลายรายการหรือแม้กระทั่ง globs

ตัวอย่างเช่น:args **/*.rbจะค้นหาไดเรกทอรีทับทิมซ้ำ ๆ ในปัจจุบันเพื่อค้นหาไฟล์ vim **/*.rbแจ้งให้ทราบว่าเรื่องนี้ยังเป็นเหมือนการเปิดเป็นกลุ่มที่มี คุณสามารถใช้findคำสั่งของเชลล์เพื่อรับรายการไฟล์ทั้งหมดในไดเรกทอรีปัจจุบันโดยการเรียกใช้:

:args `find . -type f`

คุณสามารถดูรายการ args ปัจจุบันได้:argsด้วยตัวเอง หากคุณต้องการเพิ่มหรือลบไฟล์จากรายการคุณสามารถใช้:argaddหรือ:argdeleteคำสั่งตามลำดับ

เมื่อคุณพอใจกับรายการตอนนี้คุณสามารถใช้:argdoคำสั่งอันทรงพลังของ Vim ซึ่งรันคำสั่งสำหรับทุกไฟล์ในรายการอาร์กิวเมนต์::argdo %s/search/replace/g

นี่คือเคล็ดลับบางอย่างสำหรับการค้นหา (ขึ้นอยู่กับความคิดเห็นบางส่วน):

  1. ใช้ขอบเขตของคำหากคุณต้องการค้นหา "foo" แต่ไม่ใช่ "foo_bar" ใช้\<และ\>สร้างรอบ ๆ รูปแบบการค้นหาดังนี้::argdo %s/\<search\>/foobar/g
  2. ใช้/cแฟลกการค้นหาหากคุณต้องการให้ Vim ขอคำยืนยันก่อนที่จะเปลี่ยนคำค้นหา
  3. ใช้/eแฟล็กการค้นหาหากคุณต้องการข้ามข้อผิดพลาด "pattern not found"
  4. :argdo %s/search/replace/g | updateนอกจากนี้คุณยังสามารถเลือกที่จะบันทึกไฟล์หลังจากดำเนินการค้นหา: ที่นี่:updateใช้เพราะมันจะบันทึกไฟล์เฉพาะเมื่อมีการเปลี่ยนแปลง

เปิดบัฟเฟอร์

หากคุณมีบัฟเฟอร์เปิดอยู่แล้วคุณต้องการทำการค้นหา / แทนที่คุณสามารถใช้:bufdoซึ่งจะรันคำสั่งสำหรับทุกไฟล์ในรายการบัฟเฟอร์ของคุณ ( :ls)

คำสั่งนั้นคล้ายกับ:argdo: :bufdo %s/search/replace/g

คล้ายกับ:argdoและ:bufdoมี:windoและ:tabdoดำเนินการกับหน้าต่างและแท็บตามลำดับ มักใช้น้อย แต่ก็มีประโยชน์ที่จะรู้


4
อาจเป็นความคิดที่ดีที่จะใช้การ/cตั้งค่าสถานะเพื่อยืนยันการทดแทน
romainl

3
ฉันขอแนะนำให้ใช้ขอบเขตของคำ\<และ\>รอบ ๆsearchเพื่อหลีกเลี่ยงการแทนที่คำบางส่วน
tommcdo

1
อีกความคิดเห็นหนึ่งคือไดเรกทอรีการทำงานของกลุ่มคือตามค่าเริ่มต้นซึ่งคุณเริ่มเป็นกลุ่มไม่ใช่ไดเรกทอรีของไฟล์ปัจจุบัน :cd %:p:hคุณสามารถตั้งค่าไดเรกทอรีการทำงานกับไฟล์ปัจจุบันใช้ ตัวเลือกไดเรกทอรีการทำงานอื่น ๆ ที่ระบุไว้ในvim.wikia.com/wiki/Set_working_directory_to_the_current_file
studgeek

27

สมมติว่าเรามีโครงสร้างโครงการแบบนี้:

ป้อนคำอธิบายรูปภาพที่นี่

greeting.txt ดูเหมือนว่า

ป้อนคำอธิบายรูปภาพที่นี่

และข้อมูล / age.txt ดูเหมือนว่า

ป้อนคำอธิบายรูปภาพที่นี่

สมมติว่าเราต้องการแทนที่แซมด้วยบ๊อบ นี่คือสิ่งที่เราจะทำ:

  1. ตั้งค่าไดเรกทอรีการทำงาน

    ต้องแน่ใจว่าไดเร็กตอรี่ปัจจุบันของ Vim เป็นรูทของโครงการ (จะไม่แสดงวิธีทำสิ่งนี้ที่นี่)

  2. ค้นหาไฟล์ที่มี 'Sam'

    ใช้คำสั่ง vimgrep ของ Vim เพื่อค้นหา Sam ทั้งหมดที่เกิดขึ้นภายในโครงการ (หมายเหตุ: การ**/*ค้นหาในไฟล์ทั้งหมดซ้ำ ๆ )

    :vimgrep /Sam/gj **/*
    

    นี่จะเติมรายการรายการแก้ไขด่วนด้วย Sam ของอินสแตนซ์ทั้งหมด หากคุณต้องการดูรายการ quickfix คุณสามารถใช้คำสั่ง Vim:copen ป้อนคำอธิบายรูปภาพที่นี่

  3. ทดแทนภายในไฟล์ทั้งหมดที่มี 'Sam'

    ตอนนี้เราต้องการเรียกใช้คำสั่งการแทนของ Vim ในทุก ๆ ไฟล์ในรายการ quickfix เราสามารถทำได้โดยใช้:cfdo {cmd}คำสั่งที่รัน {cmd} ในแต่ละไฟล์ในรายการ quickfix {cmd} ที่เจาะจงที่เราต้องการใช้นั้นสั้นsubstituteหรือsยาว สายเต็มจะมีลักษณะ:

    :cfdo %s/Sam/Bob/g
    

    คุณสามารถเพิ่มธง c เพื่อยืนยันการเปลี่ยนทั้งหมดหากคุณต้องการ:

    :cfdo %s/Sam/Bob/gc
    
  4. บันทึกไฟล์ทั้งหมด

    :cfdo update
    

2
ฉันชอบสิ่งนี้มากกว่านี้ มันง่ายและใช้งานได้กับ Ack (หรือปลั๊กอินใด ๆ ที่เติมหน้าต่าง QuickFix)
Zuhaib

1
นี่คือคำตอบที่ดี
Peoplee

2
ได้รับ "ไม่เขียนตั้งแต่การเปลี่ยนแปลงครั้งล่าสุด" cfdo %s/Sam/Bob/g | updateแก้ไขให้กับฉัน
hakunin

@hakunin ฉันขอแนะนำให้ตั้งค่าhiddenตัวเลือกด้วย:set hiddenหากคุณยังไม่ได้ดำเนินการ
Niko Bellic

3

แม้ว่าไม่ใช่โซลูชัน VIM หากคุณใช้ VI / VIM คุณอาจพบว่าใช้ CLI ได้ง่ายขึ้น หากต้องการเปลี่ยนไฟล์ทั้งหมดในไดเรกทอรีปัจจุบันให้ใช้perlเหมือนที่ทำกับสถานการณ์เช่นนี้:

$ perl -pi -e 's/foo/bar/g' *

หากคุณจำเป็นต้องทำในไดเรกทอรีย่อยด้วยฉันมักจะจับคู่perlกับfind:

$ find . -name '*' -print0 | xargs -0 perl -pi -e 's/foo/bar/g'

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

$ perl -pi -e 's/foo/bar/g' *.py
$ find . -name '*.py' -print0 | xargs -0 perl -pi -e 's/foo/bar/g'

1

หากต้องการแทนที่วลีด้วยวลีอื่นคุณสามารถใช้โหมด Vim Ex

ตัวอย่าง ( exเป็นนามแฝงถึงvim -E):

$ ex -s +'bufdo!%s/foo/bar/g' -cxa *.*

วนซ้ำใน bash / zsh (พร้อมglobstarชุดเช่นshopt -s globstar):

$ ex -s +'bufdo!%s/foo/bar/g' -cxa **/*.*
$ ex -s +'n **/*.*' +'bufdo!%s/foo/bar/g' -cxa

วนซ้ำ (การใช้findและละเว้นไฟล์ที่ซ่อนอยู่เช่น.gitไฟล์):

$ find . -type f -not -path '*/\.*' -exec ex -s +'bufdo!%s/foo/bar/g' -cxa {} "+"

หมายเหตุ: :bufdoคำสั่งไม่POSIX

หมายเหตุ: ไวยากรณ์-not -path '*/\.*'ถูกใช้เพื่อละเว้นไฟล์ที่ซ่อนอยู่ (เช่น.git)



0

นี่คือคำสั่งเชลล์ที่ใช้findและexแก้ไข (โดยไม่ใช้:bufdo ):

find . -name '*.rb' -exec ex +'%s/foo/bar/ge' -V1 -scwq! {} ';'

นี้จะแก้ไขในสถานที่ทุก*.rbไฟล์ในโฟลเดอร์ปัจจุบัน (ซ้ำ) และแทนที่ด้วยfoobar

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