ค้นหาซ้ำและแทนที่ในไฟล์ข้อความบน Mac และ Linux


128

ในลินุกซ์เชลล์คำสั่งต่อไปนี้จะค้นหาซ้ำและแทนที่อินสแตนซ์ทั้งหมดของ 'this' ด้วย 'that' (ฉันไม่มีลินุกซ์เชลล์อยู่ข้างหน้าฉัน แต่ควรทำ)

find . -name "*.txt" -print | xargs sed -i 's/this/that/g'

คำสั่งที่คล้ายกันบน OSX จะมีลักษณะอย่างไร?


น่าจะถูกย้ายไปapple.stackexchange.comเนื่องจากมันไม่ได้เป็นแบบทั่วไปเพียงพอสำหรับ linux หรือ devs ทั้งหมด
AlikElzin-kilaka

คำตอบ:


246

OS X ใช้เครื่องมือ BSD และ GNU ผสมกันดังนั้นควรตรวจสอบเอกสารให้ดีที่สุดเสมอ (แม้ว่าฉันจะมีมันที่lessไม่เป็นไปตามหน้า OS X ก็ตาม):

https://web.archive.org/web/20170808213955/https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/sed.1.html

sed ใช้อาร์กิวเมนต์หลัง-iเป็นส่วนขยายสำหรับการสำรองข้อมูล ระบุสตริงว่าง ( -i '') สำหรับไม่มีการสำรองข้อมูล

สิ่งต่อไปนี้ควรทำ:

LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ {} +

-type fคือการปฏิบัติที่ดีเพียง; sed จะบ่นถ้าคุณให้ไดเรกทอรีหรือมากกว่านั้น -execเป็นที่ต้องการมากกว่าxargs; คุณไม่จำเป็นต้องกังวล-print0หรืออะไรเลย {} +ที่หมายถึงการสิ้นสุดที่findจะผนวกผลลัพธ์ทั้งหมดเป็นข้อโต้แย้งให้เป็นหนึ่งในตัวอย่างของคำสั่งที่เรียกว่าแทนของใหม่ใช้มันสำหรับแต่ละผล (ข้อยกเว้นประการหนึ่งคือเมื่อมีการละเมิดจำนวนอาร์กิวเมนต์บรรทัดคำสั่งสูงสุดที่ OS อนุญาตในกรณีfindนั้นจะรันมากกว่าหนึ่งอินสแตนซ์)


2
"this" ของฉันในการแทนที่นี้มีเครื่องหมายทับ (localhost / site) - ฉันกำลังแทนที่ส่วนของ URL ในไฟล์. html .... ฉันจะทำการแทนที่ได้อย่างไร ฉันพยายามใส่เครื่องหมายคำพูดคู่ แต่ล้มเหลว
Timothy T.

6
ไวยากรณ์ sed อนุญาตให้ใช้เกือบตัวละครในสถานที่ของการเฉือนเช่นคุณสามารถใช้ตัวอักษร:% อีกทางเลือกหนึ่งคือการทับขวาหนีคั่น:sed "s%localhost/site%blah/blah%" sed "s/localhost\/site/blah\/blah/"
TaylanUB

ขอบคุณให้ฉันลองดู อย่างไรก็ตามฉันได้ลองใช้ {} เพื่อแยกเครื่องหมายทับและฉันก็ยังพบข้อผิดพลาด ...
ทิโมธี T.

16
มีใครรับillegal byte sequenceข้อผิดพลาดอีกไหม ถ้าเป็นเช่นนั้นลอง: LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ {} +มันได้ผลสำหรับฉัน
ColdTuna

10
สิ่งนี้จะแทนที่เพียงหนึ่ง ocurreny ต่อไฟล์ใช้/gสำหรับสกุลเงินหลายสกุลเช่นLC_ALL=C find . -type f -exec sed -i '' s/search/replace/g {} +
jamesjara

155

สำหรับ Mac วิธีการที่คล้ายกันมากขึ้นจะเป็นดังนี้:

find . -name '*.txt' -print0 | xargs -0 sed -i "" "s/form/forms/g"

10
ฉันหวังว่าฉันจะโหวตให้คะแนนทุกครั้งที่กลับมาและใช้มัน ตอนนี้จะอยู่ที่ +15 ง่าย
Droogans

ด้วยเหตุผลบางประการมันไม่ได้ผลสำหรับฉัน มันไม่ทำอะไรเลย ฉันอยู่ในโฟลเดอร์ form360 และฉันกำลังพยายามเปลี่ยนอินสแตนซ์สตริงทั้งหมดด้วยชื่อ easyform เป็น form360 ฉันกำลังรันคำสั่งต่อไปนี้:find . -name '*.php' -print0 | xargs -0 sed -i "" "s/easyform/form360/g"
Andres Ramos

2
สำหรับฉันนี่น่าจะเป็นคำตอบที่ถูกต้อง เป็นคนเดียวที่เหมาะกับฉัน
nosequeldeebee

1
-print0 | xargs -0 ไม่ทำงานบน mac ของฉันเมื่อชื่อไฟล์มีพื้นที่ว่าง
user2807219

1
sed:.: การแก้ไขในสถานที่ใช้งานได้กับไฟล์ปกติเท่านั้น
codelapper

14

เป็นทางเลือกอื่นฉันใช้อันนี้บน Mac OSX 10.7.5

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

เครดิตไปที่: คำตอบของ Todd Cesere


อันนี้ใช้ได้ดี! สคริปต์อื่น ๆ จะเพิ่มส่วนท้ายของบรรทัดในบางกรณีบน OSX! ขอบคุณมาก!
Sebastien Filion

14

บน Mac OSX 10.11.5 ใช้งานได้ดี:

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

xargs -I @ sed -i '' s / old-word / new-word / g '@ ได้ผลสำหรับฉันหลังจากลองคำแนะนำอื่น ๆ ที่ไม่ได้ผล ขอบคุณ!
DrB

13

ข้างต้นไม่มีผลกับ OSX

ดำเนินการดังต่อไปนี้:

perl -pi -w -e 's/SEARCH_FOR/REPLACE_WITH/g;' *.txt

1
วิธี scape "/" ถ้า SEARCH_FOR และ REPLACE_WITH เป็นเส้นทาง
rraallvv

ใช้ตัวคั่นอื่น หากคุณกำลังใช้เส้นทางโคลอนหรือไปป์ก็ใช้ได้ ตัวอย่างเช่น 's | SEARCH | REPLACE | g' วงเล็บปีกกาใช้ของเราเช่นเดียวกับใน {SEARCH} {REPLACE} "
dannysauer

1
คำถาม dito ไม่ลองใช้บน Mac - แต่ดูเหมือนว่าจะสร้างข้อผิดพลาด? ตัวอย่างเช่นเส้นทางของฉันถูกตีความว่าเป็นไฟล์? -bash: localhost / nohost: ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว
Timothy T.

สิ่งนี้ไม่เรียกเก็บซ้ำจากโฟลเดอร์ที่อยู่ลึก ระดับหนึ่งเท่านั้น.
Sergey Romanov

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับคำสั่งนี้โปรดอ่านlifehacker.com/5810026/…
kuzdu

7

เวอร์ชันที่ใช้งานได้ทั้งบน Linux และ Mac OS X (โดยเพิ่ม-eสวิตช์เป็นsed):

export LC_CTYPE=C LANG=C
find . -name '*.txt' -print0 | xargs -0 sed -i -e 's/this/that/g'

ฉันต้องทำการส่งออกจากคำตอบนี้ + บรรทัดจากคำตอบที่ยอมรับ (ฉันไม่ต้องการให้สร้างไฟล์สำรอง)
Lance

2
หากต้องการแก้ไขข้อผิดพลาด 'ลำดับไบต์ที่ผิดกฎหมาย' ให้ลองตั้งค่า LOCALE ก่อนที่จะเรียกใช้คำสั่ง: export LC_CTYPE=C && export LANG=C
cjoy

อย่าเรียกใช้สิ่งนี้ด้วย '*' แทน '* .filetype' เหมือนที่ฉันทำถ้าคุณใช้ Git หรือคุณสามารถบอกลางานที่ไม่ได้เผยแพร่ทั้งหมดของคุณ
Sergey

1
คำสั่ง sed เวอร์ชัน mac ต้องการ '' หลัง -i ดังนั้นคำตอบนี้จึงไม่ถูกต้อง
G Huxley

2

เมื่อใดก็ตามที่ฉันพิมพ์คำสั่งนี้ฉันมักจะพยายามแก้ไขหรือลืมแฟล็ก ฉันสร้าง Gist บน github จากคำตอบของ TaylanUB ที่ทำการแทนที่การค้นหาทั่วโลกจากไดเร็กทอรีปัจจุบัน นี่คือ Mac OSX โดยเฉพาะ

https://gist.github.com/nateflink/9056302

เป็นเรื่องดีเพราะตอนนี้ฉันเพิ่งเปิดเทอร์มินัลจากนั้นคัดลอก:

curl -s https://gist.github.com/nateflink/9056302/raw/findreplaceosx.sh | ทุบตี -s "find-a-url.com" "replace-a-url.com"

คุณอาจได้รับข้อผิดพลาดของลำดับไบต์แปลก ๆ ดังนั้นนี่คือรหัสเต็ม:

#!/bin/bash
#By Nate Flink

#Invoke on the terminal like this
#curl -s https://gist.github.com/nateflink/9056302/raw/findreplaceosx.sh | bash -s "find-a-url.com" "replace-a-url.com"

if [ -z "$1" ] || [ -z "$2" ]; then
  echo "Usage: ./$0 [find string] [replace string]"
  exit 1
fi

FIND=$1
REPLACE=$2

#needed for byte sequence error in ascii to utf conversion on OSX
export LC_CTYPE=C;
export LANG=C;

#sed -i "" is needed by the osx version of sed (instead of sed -i)
find . -type f -exec sed -i "" "s|${FIND}|${REPLACE}|g" {} +
exit 0

2

นี่คือสิ่งที่ใช้งานได้ของฉัน บน mac OS X 10.10.4

grep -e 'this' -rl . | xargs sed -i '' 's/this/that/g'

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



1

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

find . -type f -name '*.txt' -exec sed -i '' s/thistext/newtext/ {} +

คุณต้องรันคำสั่งนี้หลาย ๆ ครั้ง b / c sed regex ของคุณต้องการ a gในตอนท้ายมิฉะนั้นจะแทนที่การเกิดครั้งแรกthistextในบรรทัดเท่านั้น ดังนั้น regex ของคุณควรเป็นs/thistext/newtext/g
Les Nightingill

0

https://bitbucket.org/masonicboom/serpเป็นยูทิลิตี้ go (เช่นข้ามแพลตฟอร์ม) ทดสอบบน OSX ซึ่งทำการค้นหาซ้ำและแทนที่ข้อความในไฟล์ภายในไดเร็กทอรีที่กำหนดและยืนยันการแทนที่แต่ละครั้ง เป็นเรื่องใหม่ดังนั้นอาจมีปัญหา

ลักษณะการใช้งาน:

$ ls test
a  d  d2 z
$ cat test/z
hi
$ ./serp --root test --search hi --replace bye --pattern "*"                         
test/z: replace hi with bye? (y/[n]) y
$ cat test/z
bye


-3

คำสั่งบน OSX ควรเหมือนกับ Unix ทุกประการภายใต้ UI ที่สวยงาม


ฉันคิดว่ามาก แต่ไม่ มันใส่. / ไว้หน้าไฟล์เมื่อป้อนให้กับ sed ดังนั้น sed จึงบ่นว่า 'รหัสคำสั่งไม่ถูกต้อง' บางทีฉันก็เหนื่อย ;-)
แจ็ค

@JacobusR โปรดตัดและวางจากเทอร์มินัล OSX ของคุณ - คุณต้องป้อนสิ่งที่แตกต่างออกไปเล็กน้อย
glenn jackman

3
คุณอาจต้องการที่-print0เพิ่มให้กับfindธงและ-0ไปที่xargsธง
jmtd

คุณยังสามารถใช้-exec sed -i s/this/that/g {} \+แทน-printและ xargs ได้
Marian

@JacobusR - ใช้งานได้แม้ว่าจะมีชื่อพา ธ "./" นำหน้าก็ตาม อย่างไรก็ตามหากมีช่องว่างในชื่อไฟล์ให้พูดว่า "./jacobus \ R.txt" การใช้งานxargsอาจเห็น "./jacobus" ที่คั่นด้วยช่องว่างเป็นไฟล์ที่จะส่งผ่านไปยังsedและตามด้วย "R.txt" ซึ่งไม่มีอยู่จริง
Brett Hale

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