วิธีการแทนที่สตริงในหลาย ๆ ไฟล์ในบรรทัดคำสั่ง linux


460

ฉันต้องการแทนที่สตริงในไฟล์จำนวนมากในโฟลเดอร์ที่มีsshการเข้าถึงเซิร์ฟเวอร์เท่านั้น ฉันจะทำสิ่งนี้ได้อย่างไร

คำตอบ:


601
cd /path/to/your/folder
sed -i 's/foo/bar/g' *

การเกิดขึ้นของ "foo" จะถูกแทนที่ด้วย "บาร์"

ในระบบ BSD เช่น macOS คุณต้องให้ส่วนขยายการสำรองข้อมูลอย่าง-i '.bak'อื่นหรือ "เสี่ยงต่อความเสียหายหรือเนื้อหาบางส่วน" ต่อ manpage

cd /path/to/your/folder
sed -i '.bak' 's/foo/bar/g' *

13
ดูเหมือนจะไม่เหมาะกับฉันหากสตริงมีช่องว่างหรืออักขระพิเศษอยู่ในนั้น ความคิดใด ๆ ที่อาจเป็นไปได้หรือฉันจะต้องหลบหนีพวกเขาได้อย่างไร? ขอบคุณ!
Matthew Herbst

13
อย่างน้อยสำหรับรุ่นของฉันsed, -iต้องสตริงหลังจากที่มันซึ่งถูกผนวกเข้ากับชื่อไฟล์เก่า ดังนั้นsed -i .bak 's/foo/bar/g' *.xxย้าย.xxไฟล์ทั้งหมดไปยัง.xx.bakชื่อเทียบเท่าแล้วสร้าง.xxไฟล์ที่มีการทดแทน foo → bar
Anaphory

24
หากใครต้องการค้นหาตัวเลือกเพิ่มเติมมีคำตอบเกี่ยวกับ unix stack exchange ซึ่งครอบคลุมกรณีการใช้งานที่มากขึ้นไซต์unix.stackexchange.com/a/112024/13488
Reddy

19
@MatthewHerbst ที่จะหลบหนีช่องว่างการใช้ \ sed -i 's/foo\ with\ spaces/bar/g' *เช่น ฉันคิดว่าคุณรู้มานานแล้ว ... แต่วิธีนี้จะทำให้คนอื่นค้นพบปัญหาเดียวกัน
manuelvigarcia

5
สำหรับสิ่งที่เกิดซ้ำคุณสามารถลองทำสิ่งต่อไปนี้ โปรดทราบว่ามันไม่ทำงานหากรายการไฟล์มีขนาดใหญ่มาก sed -i -e 's/foo/bar/g' $(find /home/user/base/dir)
ชาวสกอต

243

คล้ายกับคำตอบของคาสปาร์ แต่ใช้แฟล็ก g เพื่อแทนที่เหตุการณ์ทั้งหมดในบรรทัด

find ./ -type f -exec sed -i 's/string1/string2/g' {} \;

สำหรับกรณีทั่วโลกที่ไม่สำคัญ:

find ./ -type f -exec sed -i 's/string1/string2/gI' {} \;

23
หากคุณอยู่บน OSX และรูปแบบของคุณอาจมีจุดและคุณต้องการแทนที่แบบแทนที่ (ไม่มีไฟล์สำรอง) คุณควรใช้LC_ALL=C find ./ -type f -exec sed -i '' -e 's/proc.priv/priv/g' {} \;(ดูโพสต์นี้และสิ่งนี้ )
Jonathan H

2
วิธีนี้ใช้ได้ผลสำหรับฉันอย่างแน่นอนเนื่องจากสามารถใช้การกรองด้วย -name "* .js" '
Marcello de Sales

1
ตัวเลือกที่ละเอียดจะเย็น แต่คุณสามารถ grep อีกครั้งเพื่อดูว่ามีการเปลี่ยนแปลง หมายเหตุ: สำหรับไวด์การ์ดให้ลอง '-name "* .php"' และ grep ไม่ดีสำหรับการเรียกซ้ำและไวด์การ์ดคุณต้องเพิ่ม--include=*.whateverด้วย -r
PJ Brunet

12
อย่าทำสิ่งนี้จากรากของ repo Git ที่เช็คเอาท์ .git/คุณอาจเสียหายได้ตั้งใจฐานข้อมูลใน อย่าลืมcdลงไปสู่ระดับที่ต่ำกว่า
erikprice

1
ฉันเพียงแค่ทำอย่างนี้ใน repo คอมไพล์ของฉันและตอนนี้จะส่งกลับgit status error: bad index file sha1 signature.... fatal: index file corruptสิ่งที่ช่วยให้?
จิน

165

คำตอบของ @ kev นั้นดี แต่มีผลกับไฟล์ในไดเรกทอรีทันทีตัวอย่างด้านล่างนี้ใช้ grep เพื่อค้นหาไฟล์ซ้ำ ๆ มันเหมาะกับฉันทุกครั้ง

grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @

การแบ่งคำสั่ง

grep -r : -เรียกซ้ำอ่านไฟล์ซ้ำทั้งหมดภายใต้แต่ละไดเร็กทอรี
grep -l : - พิมพ์ด้วยการจับคู่พิมพ์ชื่อของแต่ละไฟล์ที่มีการจับคู่แทนการพิมพ์บรรทัดที่ตรงกัน
grep -i : ละเลยกรณี

xargs : แปลง STDIN เป็นอาร์กิวเมนต์ให้ทำตามคำตอบนี้
คำสั่ง xargs -i @ ~ มี @ ~ : ตัวยึดตำแหน่งสำหรับอาร์กิวเมนต์ที่จะใช้ในตำแหน่งเฉพาะในคำสั่ง ~ ~เครื่องหมาย @ เป็นตัวยึดตำแหน่งซึ่งสามารถแทนที่ด้วยสตริงใด ๆ

sed -i : แก้ไขไฟล์โดยไม่ต้องสำรองข้อมูล
sed s / regexp / ทดแทน / : แทนการจับคู่สายregexpกับการเปลี่ยน
seds / regexp / replace / g : globalทำการทดแทนสำหรับแต่ละการแข่งขันแทนการแข่งขันครั้งแรกเท่านั้น


13
สิ่งนี้ไม่ได้ผลสำหรับฉัน แต่สิ่งนี้ทำได้:grep --include={*.php,*.html,*.js} -rnl './' -e "old-word" | xargs -i@ sed -i 's/old-word/new-word/g' @
Dennis

7
@pymarco คุณช่วยอธิบายคำสั่งนี้ได้ไหม? ฉันไม่รู้ว่าทำไมคุณต้องใช้ xargs แทนที่จะใช้ sed หลังจาก|นั้นทำไม-iในคำสั่ง xargs ฉันอ่านในคู่มือมันเลิกใช้แล้วและควรใช้-Iแทน และ@ใช้เป็นตัวคั่นสำหรับจุดเริ่มต้นและจุดสิ้นสุดสำหรับรูปแบบหรือไม่
Edson Horacio Junior

2
คำถามนี้เป็นคำถามเฉพาะสำหรับ linux
pymarco

6
บน osx ไม่เป็นไร:grep -rli 'old-word' * | xargs -I@ sed -i '' 's/2.0.0/latest/g' @
Philippe Sultan

1
มันจะดีถ้าคุณทำลายตัวเลือก ( rli) บางตัวและ@เครื่องหมายตัวอย่าง
Roymunson

37

สิ่งนี้ใช้ได้กับฉัน:

find ./ -type f -exec sed -i 's/string1/string2/' {} \;

howerver sed -i 's/string1/string2/g' *นี้ไม่ได้: อาจจะ "foo" ไม่ได้หมายถึงเป็น string1 และ "bar" ไม่ใช่ string2


1
เป็นเพราะ sed ปฏิบัติต่อสัญลักษณ์แทน * ต่างกัน [abc] * หมายถึงจำนวนอักขระของชุด {a, b, c} โดยพลการ [a-z0-9] * ใช้งานได้ใกล้เคียงกับ wildcard *
thepiercingarrow

8
สำหรับการใช้งาน OSX:find ./ -type f -exec sed -i '' -e 's/string1/string2/' {} \;
Shaheen Ghiassy

32

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

เพื่อการใช้งานที่รวดเร็วที่สุดคุณอาจพบว่าคำสั่งrplนั้นง่ายต่อการจดจำ นี่คือการแทนที่ (foo -> bar), ซ้ำในไฟล์ทั้งหมด:

rpl -R foo bar .

คุณอาจต้องติดตั้ง ( apt-get install rplหรือคล้ายกัน)

อย่างไรก็ตามสำหรับงานที่ยากขึ้นซึ่งเกี่ยวข้องกับการแสดงออกปกติและการทดแทนกลับหรือเปลี่ยนชื่อไฟล์เช่นเดียวกับการค้นหาและแทนที่เครื่องมือทั่วไปและทรงพลังที่สุดที่ฉันรู้คือreprenสคริปต์ Python ขนาดเล็กที่ฉันเขียนกลับมาบางส่วน การเปลี่ยนชื่อและการเปลี่ยนโครงสร้างงานใหม่ เหตุผลที่คุณอาจชอบ:

  • รองรับการเปลี่ยนชื่อไฟล์รวมถึงการค้นหาและแทนที่เนื้อหาไฟล์
  • ดูการเปลี่ยนแปลงก่อนที่คุณจะยอมรับการดำเนินการค้นหาและแทนที่
  • สนับสนุนการแสดงออกปกติด้วยการทดแทนด้านหลังทั้งคำตัวพิมพ์เล็กและตัวพิมพ์เล็ก (แทน foo -> bar, Foo -> Bar, FOO -> BAR) โหมด
  • ใช้งานได้กับการเปลี่ยนได้หลายแบบรวมถึง swaps (foo -> bar และ bar -> foo) หรือชุดของการแทนที่ที่ไม่ซ้ำกัน (foo -> bar, f -> x)

ที่จะใช้มัน, pip install repren. ตรวจสอบ READMEสำหรับตัวอย่าง


1
ว้าว repren เป็นเลิศ! เพียงแค่ใช้มันเพื่อเปลี่ยนส่วนหนึ่งของคำที่อยู่ในชื่อชั้นเรียนวิธีการและตัวแปรในขณะที่การเปลี่ยนชื่อไฟล์ให้ตรงกับส่วนหัว 1,000 + C ++ และไฟล์ต้นฉบับและมันทำงานได้อย่างสมบูรณ์แบบเป็นครั้งแรกด้วยคำสั่งเดียว ขอบคุณ!
Bob Kocisko


20

ในการแทนที่เส้นทางภายในไฟล์ (หลีกเลี่ยงอักขระเลี่ยง) คุณอาจใช้คำสั่งต่อไปนี้:

sed -i 's@old_path@new_path@g'

เครื่องหมาย @ หมายความว่าควรละเว้นอักขระพิเศษทั้งหมดในสตริงต่อไปนี้


2
สิ่งที่ฉันกำลังมองหาในคำตอบอื่น ๆ ทั้งหมด คือวิธีการจัดการกับตัวละครพิเศษเช่นเมื่อเปลี่ยนสตริงที่เป็นเส้นทาง ขอบคุณ. ดูเหมือนคำตอบที่ใหญ่มากในคำตอบอื่น ๆ
แรงบันดาลใจ

19

ในกรณีที่สตริงของคุณมีเครื่องหมายทับ (/) อยู่ข้างในคุณสามารถเปลี่ยนตัวคั่นเป็น '+'

find . -type f -exec sed -i 's+http://example.com+https://example.com+g' {} +

คำสั่งนี้จะทำงานซ้ำในไดเรกทอรีปัจจุบัน


ขอบคุณ! ช่วยเปลี่ยนภาระการอ้างอิง../domain.comถึงdomain.com
Jack Rogers

12

บรรทัดแรกของ "foo" จะถูกแทนที่ด้วย "bar" และคุณสามารถใช้บรรทัดที่สองเพื่อตรวจสอบ

grep -rl 'foo' . | xargs sed -i 's/foo/bar/g'
grep 'foo' -r * | awk -F: {'print $1'} | sort -n | uniq -c

6
ทำไมคุณเชื่อมโยงไปยังบล็อกของคุณ มันมีข้อความเหมือนกับคำตอบของคุณ
DavidPostill

1
ฉันชอบgrep -rl 'foo' . | xargs sed -i 's/foo/bar/g'
Prachi

10

หากคุณมีรายการไฟล์ที่คุณสามารถใช้ได้

replace "old_string" "new_string" -- file_name1 file_name2 file_name3

หากคุณมีไฟล์ทั้งหมดคุณสามารถใช้

replace "old_string" "new_string" -- *

หากคุณมีรายการไฟล์ที่มีนามสกุลคุณสามารถใช้

replace "old_string" "new_string" -- *.extension

2
อันที่จริง "- ไฟล์" ควรเป็น "-" อย่างน้อยในเวอร์ชันของฉัน
simpleuser

4
ยูทิลิตี้นี้แจกจ่ายในแพ็คเกจ MySQL
Dmitry Ginzburg

2
แม้ว่าฉันอยากจะขอบคุณวิธีแก้ปัญหาที่ทำงานได้โดยไม่ต้องอ้างถึงบรรทัดปกติเพื่อเป็นการแสดงออกปกติ
Dmitry Ginzburg

1
มันใช้งานได้ดี - และถ้าคุณต้องการแทนที่สตริงทั้งหมดในหลายไฟล์ซึ่งลงท้ายด้วยเช่น ".txt" คุณสามารถทำได้replace "old_string" "new_string" -- *.txt
tsveti_iko

1
มันจะเป็นการดีกว่าถ้าคุณจะเพิ่มreplaceยูทิลิตี้นี้ หากไม่มีข้อมูลนี้คำตอบนี้จะไม่สมบูรณ์
Sitesh

8

"คุณสามารถใช้ find และ sed แต่ฉันพบว่า perl บรรทัดเล็ก ๆ นี้ทำงานได้ดี

perl -pi -w -e 's/search/replace/g;' *.php
  • -e หมายถึงรันรหัสบรรทัดต่อไปนี้
  • -i หมายถึงการแก้ไขในสถานที่
  • - เขียนคำเตือน
  • -p วน

"(สกัดจากhttp://www.liamdelahunty.com/tips/linux_search_and_replace_multiple_files.php )

ผลลัพธ์ที่ดีที่สุดของฉันมาจากการใช้ Perl และ grep (เพื่อให้แน่ใจว่าไฟล์มีการแสดงออกการค้นหา)

perl -pi -w -e 's/search/replace/g;' $( grep -rl 'search' )

8

ให้คุณต้องการค้นหาสตริงsearchและแทนที่ด้วยreplaceไฟล์หลาย ๆ ไฟล์นี่คือสูตรทดสอบบรรทัดเดียวของฉัน :

grep -RiIl 'search' | xargs sed -i 's/search/replace/g'

คำอธิบาย grep ด่วน:

  • -R - การค้นหาแบบเรียกซ้ำ
  • -i - ตัวพิมพ์เล็กและตัวพิมพ์ใหญ่
  • -I - ข้ามไฟล์ไบนารี (คุณต้องการข้อความใช่ไหม?)
  • -l- พิมพ์รายการง่าย ๆ เป็นเอาท์พุท จำเป็นสำหรับคำสั่งอื่น ๆ

เอาต์พุต grep จะถูกไพพ์ไปยัง sed (ผ่าน xargs) ซึ่งใช้เพื่อแทนที่ข้อความจริง การ-iตั้งค่าสถานะจะเปลี่ยนไฟล์โดยตรง ลบออกสำหรับโหมด "dry run"


4

ฉันได้ปรุงวิธีการแก้ปัญหาของตัวเองก่อนที่จะพบคำถามนี้ (และคำตอบ) ฉันค้นหาชุดค่าผสมต่าง ๆ ของ "แทนที่" "หลายอย่าง" และ "xml" เพราะนั่นเป็นแอปพลิเคชันของฉัน แต่ไม่พบชุดนี้โดยเฉพาะ

ปัญหาของฉัน: ฉันมีไฟล์ xml แบบสปริงพร้อมข้อมูลสำหรับกรณีทดสอบซึ่งมีวัตถุที่ซับซ้อน refactor บนซอร์สโค้ดจาวาเปลี่ยนคลาสจำนวนมากและไม่ได้ใช้กับไฟล์ข้อมูล xml ในการบันทึกข้อมูลกรณีทดสอบฉันจำเป็นต้องเปลี่ยนชื่อคลาสทั้งหมดในไฟล์ xml ทั้งหมดซึ่งกระจายอยู่ในหลายไดเรกทอรี ทั้งหมดในขณะที่บันทึกสำเนาสำรองของไฟล์ xml ดั้งเดิม (แม้ว่านี่ไม่ใช่สิ่งที่จำเป็นเนื่องจากการควบคุมเวอร์ชันจะช่วยฉันที่นี่)

ฉันกำลังมองหาชุดค่าผสมของfind+ sedเพราะมันใช้ได้กับฉันในสถานการณ์อื่น ๆ แต่ไม่สามารถใช้ทดแทนได้หลายรายการพร้อมกัน

จากนั้นฉันก็พบการถามการตอบสนองของ Ubuntuและมันช่วยให้ฉันสร้างบรรทัดคำสั่งของฉัน:

find -name "*.xml" -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;

และมันก็ทำงานได้อย่างสมบูรณ์แบบ (กรณีของฉันมีการเปลี่ยนได้หกแบบ) แต่โปรดทราบว่ามันจะสัมผัสไฟล์ * .xml ทั้งหมดภายใต้ไดเรกทอรีปัจจุบัน ด้วยเหตุนี้และหากคุณรับผิดชอบระบบควบคุมเวอร์ชันคุณอาจต้องการกรองก่อนและส่งต่อเฉพาะsedผู้ที่มีสตริงที่คุณต้องการเท่านั้น ชอบ:

find -name "*.xml" -exec grep -e "firstWord" -e "secondWord" -e "thirdWord" {} \; -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;

และสำหรับ windows ฉันเพิ่งพบว่ามีวิธีหาสตริง - ไม่ได้ตรวจสอบวิธีการแทนที่ - ในคำสั่งเดียว: findstr /spin /c:"quéquieresbuscar" *.xml มันจะมีประโยชน์
manuelvigarcia


3

ง่อยจริง ๆ แต่ฉันไม่สามารถรับคำสั่ง sed ใด ๆ ให้ทำงานบน OSX ได้ดังนั้นฉันจึงทำสิ่งที่โง่แทน:

:%s/foo/bar/g
:wn

^ - คัดลอกทั้งสามบรรทัดลงในคลิปบอร์ดของฉัน (ใช่รวมบรรทัดใหม่ที่ลงท้ายด้วย) จากนั้น:

vi *

และกด command-v ค้างไว้จนกระทั่งข้อความแจ้งว่าไม่มีไฟล์เหลืออยู่

ใบ้ ... hacky ... ที่มีประสิทธิภาพ ...


3

ใน MacBook Pro ฉันใช้สิ่งต่อไปนี้ (ได้รับแรงบันดาลใจจากhttps://stackoverflow.com/a/19457213/6169225 ):

sed -i '' -e 's/<STR_TO_REPLACE>/<REPLACEMENT_STR>/g' *

-i '' จะทำให้แน่ใจว่าคุณไม่ได้สำรองข้อมูล

-e สำหรับ regex ที่ทันสมัย


3
-eแค่บอกว่า sed โทเค็นถัดไปคือคำสั่ง สำหรับนิพจน์ทั่วไปที่ขยายให้ใช้-Eแทน
Benjamin W.

2

ตัวแก้ไขสตรีมจะแก้ไขหลายไฟล์“ inplace” เมื่อเรียกใช้โดยใช้-iสวิตช์ซึ่งใช้ไฟล์สำรองที่ลงท้ายด้วยอาร์กิวเมนต์ ดังนั้น

sed -i.bak 's/foo/bar/g' *

แทนที่fooด้วยbarในไฟล์ทั้งหมดในโฟลเดอร์นี้ แต่ไม่ได้ลงไปในโฟลเดอร์ย่อย อย่างไรก็ตามสิ่งนี้จะสร้าง.bakไฟล์ใหม่สำหรับทุกไฟล์ในไดเรกทอรีของคุณ ในการทำเช่นนี้ซ้ำสำหรับไฟล์ทั้งหมดในไดเรกทอรีนี้และไดเรกทอรีย่อยทั้งหมดคุณต้องมีผู้ช่วยเช่นfindเพื่อสำรวจทรีไดเรกทอรี

find ./ -print0 | xargs -0 sed -i.bak 's/foo/bar/g' *

findอนุญาตให้คุณ จำกัด เพิ่มเติมเกี่ยวกับไฟล์ที่จะแก้ไขโดยการระบุอาร์กิวเมนต์เพิ่มเติมเช่นfind ./ -name '*.php' -or -name '*.html' -print0หากจำเป็น


หมายเหตุ: GNU sedไม่ต้องการไฟล์ที่สิ้นสุดsed -i 's/foo/bar/g' *จะทำงานได้เช่นกัน FreeBSD sedต้องการส่วนขยาย แต่อนุญาตให้มีช่องว่างระหว่างนั้นsed -i .bak s/foo/bar/g *ได้


2

สคริปต์สำหรับคำสั่ง multiedit

multiedit [-n PATTERN] OLDSTRING NEWSTRING

จากคำตอบของ Kaspar ฉันสร้าง bash script เพื่อยอมรับอาร์กิวเมนต์บรรทัดคำสั่งและเลือกที่จะ จำกัด ชื่อไฟล์ที่ตรงกับรูปแบบ บันทึกใน $ PATH ของคุณและทำการปฏิบัติการจากนั้นใช้คำสั่งด้านบน

นี่คือสคริปต์:

#!/bin/bash
_help="\n
Replace OLDSTRING with NEWSTRING recursively starting from current directory\n
multiedit [-n PATTERN] OLDSTRING NEWSTRING\n

[-n PATTERN] option limits to filenames matching PATTERN\n
Note: backslash escape special characters\n
Note: enclose STRINGS with spaces in double quotes\n
Example to limit the edit to python files:\n
multiedit -n \*.py \"OLD STRING\" NEWSTRING\n"

# ensure correct number of arguments, otherwise display help...
if [ $# -lt 2 ] || [ $# -gt 4 ]; then echo -e $_help ; exit ; fi
if [ $1 == "-n" ]; then  # if -n option is given:
        # replace OLDSTRING with NEWSTRING recursively in files matching PATTERN
        find ./ -type f -name "$2" -exec sed -i "s/$3/$4/g" {} \;
else
        # replace OLDSTRING with NEWSTRING recursively in all files
        find ./ -type f -exec sed -i "s/$1/$2/" {} \;
fi

1

หากไฟล์มีเครื่องหมายแบ็กสแลช (โดยทั่วไปคือพา ธ ) คุณสามารถลองสิ่งต่อไปนี้:

sed -i -- 's,<path1>,<path2>,g' *

อดีต:

sed -i -- 's,/foo/bar,/new/foo/bar,g' *.sh (in all shell scripts available)

1

เพื่อรักษาโหนดภาษาอังกฤษส่วนบุคคลของฉันฉันเขียนสคริปต์ยูทิลิตี้ที่ช่วยในการแทนที่สตริงเก่า / ใหม่หลายคู่สำหรับไฟล์ทั้งหมดภายใต้ไดเรกทอรีซ้ำ

สตริงเก่า / ใหม่หลายคู่ได้รับการจัดการในแผนที่แฮช

dir สามารถตั้งค่าผ่านทางบรรทัดคำสั่งหรือตัวแปรสภาพแวดล้อม, แผนที่เป็นรหัสยากในสคริปต์ แต่คุณสามารถปรับเปลี่ยนรหัสที่จะโหลดจากไฟล์ถ้าจำเป็น

มันต้องทุบตี 4.2 เนื่องจากคุณสมบัติใหม่บางอย่าง

en_standardize.sh:

#! /bin/bash
# (need bash 4.2+,)
# 
# Standardize phonetic symbol of English.
# 
# format:
#   en_standardize.sh [<dir>]
# 
# params:
# * dir
#   target dir, optional,
#   if not specified then use environment variable "$node_dir_en",
#   if both not provided, then will not execute,
# * 
# 

paramCount=$#

# figure target dir,
if [ $paramCount -ge 1 ]; then # dir specified
    echo -e "dir specified (in command):\n\t$1\n"
    targetDir=$1
elif [[ -v node_dir_en ]]; then # environable set,
    echo -e "dir specified (in environment vairable):\n\t$node_dir_en\n"
    targetDir=$node_dir_en
else # environable not set,
    echo "dir not specified, won't execute"
    exit
fi

# check whether dir exists,
if [ -d $targetDir ]; then
    cd $targetDir
else
    echo -e "invalid dir location:\n\t$targetDir\n"
    exit
fi

# initial map,
declare -A itemMap
itemMap=( ["ɪ"]="i" ["ː"]=":" ["ɜ"]="ə" ["ɒ"]="ɔ" ["ʊ"]="u" ["ɛ"]="e")

# print item maps,
echo 'maps:'
for key in "${!itemMap[@]}"; do
    echo -e "\t$key\t->\t${itemMap[$key]}"
done
echo -e '\n'

# do replace,
for key in "${!itemMap[@]}"; do
    grep -rli "$key" * | xargs -i@ sed -i "s/$key/${itemMap[$key]}/g" @
done

echo -e "\nDone."
exit

1

การใช้คำสั่ง ack จะเร็วขึ้นมากเช่นนี้:

ack '25 Essex' -l | xargs sed -i 's/The\ fox \jump/abc 321/g'

นอกจากนี้หากคุณมีพื้นที่สีขาวในผลการค้นหา คุณต้องหลบหนี


0

ฉันให้ตัวอย่างสำหรับการแก้ไขข้อผิดพลาด shebang ทั่วไปในแหล่งหลาม

คุณสามารถลองใช้วิธี grep / sed นี่คืออันที่ทำงานกับ GNU sed และจะไม่ทำลาย repit คอมไพล์:

$ grep -rli --exclude '*.git*' '#!/usr/bin/python' . | xargs -I {} \
gsed -i '' -e 's/#!\/usr\/bin\/python/#!\/usr\/bin\/env python/' {}

หรือคุณสามารถใช้greptile :)

$ greptile -x .py -l -i -g '#!/usr/bin/env python' -r '#!/usr/bin/python' .

ฉันเพิ่งทดสอบบทแรกและข้อที่สองก็ใช้ได้เช่นกัน ระวังตัวละครในการหลบหนีฉันคิดว่ามันน่าจะง่ายกว่าถ้าใช้ greptile ในกรณีส่วนใหญ่ แน่นอนคุณสามารถทำสิ่งที่น่าสนใจมากมายกับ sed และมันอาจจะดีกว่าถ้าคุณใช้มันด้วย xargs


0

ฉันพบอันนี้จากโพสต์อื่น (จำไม่ได้ว่า) และในขณะที่ไม่หรูหราที่สุดมันง่ายและเป็นผู้ใช้ Linux มือใหม่ทำให้ฉันไม่มีปัญหา

for i in *old_str* ; do mv -v "$i" "${i/\old_str/new_str}" ; done

หากคุณมีช่องว่างหรืออักขระพิเศษอื่น ๆ ให้ใช้ \

for i in *old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done

สำหรับสตริงในไดเรกทอรีย่อยให้ใช้ **

for i in *\*old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done

0

คำสั่งด้านล่างสามารถใช้เพื่อค้นหาไฟล์ก่อนและแทนที่ไฟล์:

find . | xargs grep 'search string' | sed 's/search string/new string/g'

ตัวอย่างเช่น

find . | xargs grep abc | sed 's/abc/xyz/g'

0

มีวิธีที่ง่ายกว่าโดยใช้ไฟล์สคริปต์แบบง่าย:

   # sudo chmod +x /bin/replace_string_files_present_dir

เปิดไฟล์ใน gedit หรือแก้ไขที่คุณเลือกฉันใช้ gedit ที่นี่

   # sudo gedit /bin/replace_string_files_present_dir

จากนั้นในตัวแก้ไขวางต่อไปนี้ในไฟล์

   #!/bin/bash
   replace "oldstring" "newstring" -- *
   replace "oldstring1" "newstring2" -- *
   #add as many lines of replace as there are your strings to be replaced for 
   #example here i have two sets of strings to replace which are oldstring and 
   #oldstring1 so I use two replace lines.

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

นำทางไปยังไดเรกทอรีที่คุณมีไฟล์หลายไฟล์ที่คุณต้องการแก้ไข จากนั้นเรียกใช้:

  #replace_string_files_present_dir

กด enter แล้วจะเป็นการแทนที่สตริงเก่าและoldstring1ในไฟล์ทั้งหมดที่มีสตริงที่ถูกต้องและสตริงที่ 1 ใหม่ตามลำดับ

มันจะข้ามไดเรกทอรีและไฟล์ทั้งหมดที่ไม่มีสตริงเก่า

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

#replace_string_files_present_dir

สิ่งที่คุณต้องทำคือให้แน่ใจว่าคุณได้รวมหรือเพิ่มสตริงการแทนที่ทั้งหมดตามที่ฉันแสดงให้คุณเห็นด้านบน:

replace "oldstring" "newstring" -- *

ในตอนท้ายของไฟล์/ bin / replace_string_files_present_dir

หากต้องการเพิ่มสตริงแทนที่ใหม่เพียงแค่เปิดสคริปต์ที่เราสร้างขึ้นโดยพิมพ์ข้อความต่อไปนี้ในเทอร์มินัล:

sudo gedit /bin/replace_string_files_present_dir

ไม่ต้องกังวลเกี่ยวกับจำนวนสตริงแทนที่ที่คุณเพิ่มพวกเขาจะไม่มีผลหากไม่พบสตริงเก่า


โดยปกติแล้วเมื่อมีคนถามว่า "$ $ อะไรก็ตาม" ในทุบตีพวกเขาจะขอรุ่นกะทัดรัดที่จะรวมไว้ในคำสั่งงานสคริปต์หรือCI (พูด a .gitlab-ci.ymlหรือ a travis.yml) ทุกรอบที่มีการเขียนสคริปต์เพื่อดำเนินการในภายหลังคือรูปแบบการต่อต้านเพราะคุณจะต้องสคริปต์การสร้างสคริปต์ (และฉันยุ่งมากเวลา)
zar3bski

-4

$ แทนที่ "จาก" "ถึง" - `find / path / to / folder -type f`

(แทนที่ - ยูทิลิตี้แทนที่สตริงของระบบฐานข้อมูล MySQL)

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