Làm thế nào để thực hiện tìm / đệ quy chuỗi bằng awk hoặc sed?


674

Làm cách nào để tìm và thay thế mọi lần xuất hiện của:

subdomainA.example.com

với

subdomainB.example.com

trong mỗi tệp văn bản dưới /home/www/cây thư mục đệ quy?


93
Mẹo: Không thực hiện các thao tác bên dưới trong cây thanh toán svn ... nó sẽ ghi đè lên các tệp thư mục ma thuật .svn.
J. Polfer

7
trời ơi, đây chính xác là những gì tôi vừa làm Nhưng nó đã làm việc và dường như không làm hại gì. Điều tồi tệ nhất có thể xảy ra là gì?
J. Katzwinkel

5
@ J.Katzwinkel: ít nhất, nó có thể làm hỏng tổng kiểm tra, có thể làm hỏng kho lưu trữ của bạn.
ninjagecko

3
Mẹo nhanh cho tất cả những người sử dụng sed: Nó sẽ thêm các dòng mới vào tập tin của bạn. Nếu bạn không muốn chúng, trước tiên hãy thực hiện tìm kiếm thay thế không phù hợp với bất cứ điều gì và cam kết điều đó với git. Sau đó làm một cái thật. Sau đó rebase tương tác và xóa cái đầu tiên.
funroll

5
Bạn có thể loại trừ một thư mục, chẳng hạn như git, từ kết quả bằng cách sử dụng -path ./.git -prune -otrong find . -path ./.git -prune -o -type f -name '*matchThisText*' -print0trước khi đường ống để xargs
devinbost

Câu trả lời:


849
find /home/www \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'

-print0yêu findcầu in từng kết quả được phân tách bằng ký tự null, thay vì một dòng mới. Trong trường hợp không chắc là thư mục của bạn có các tệp có dòng mới trong tên, điều này vẫn cho phép xargslàm việc với tên tệp chính xác.

\( -type d -name .git -prune \)là một biểu thức hoàn toàn bỏ qua tất cả các thư mục có tên .git. Bạn có thể dễ dàng mở rộng nó, nếu bạn sử dụng SVN hoặc có các thư mục khác mà bạn muốn giữ lại - chỉ cần khớp với nhiều tên khác. Nó gần tương đương với -not -path .git, nhưng hiệu quả hơn, vì thay vì kiểm tra mọi tệp trong thư mục, nó bỏ qua hoàn toàn. Sau -okhi nó được yêu cầu vì cách -prunethực sự hoạt động.

Để biết thêm thông tin, xem man find.


132
Trên OSX bạn có thể gặp phải sed: 1: "...": invalid command code .vấn đề. Có vẻ như tùy chọn -i mong đợi phần mở rộng và phân tích 's/../...'lệnh ra. Giải pháp: vượt qua tùy chọn '' to -i giống như sed -i '' 's/....
Robert Lujo

6
Lưu ý: nếu bạn sử dụng điều này trên một thư mục và tự hỏi tại sao svn stkhông hiển thị thay đổi, thì đó là vì bạn cũng đã sửa đổi các tệp trong thư mục .svn! Sử dụng find . -maxdepth 1 -type f -print0 | xargs -0 sed -i 's/toreplace/replaced/g'thay thế.
ACK_stoverflow

57
Ngoài ra, hãy cẩn thận nếu bạn đang ở trong một repo git. Tôi nghĩ rằng tôi thông minh bằng cách thử nghiệm điều này trên một nhánh rõ ràng để tôi có thể hoàn nguyên nếu nó làm điều gì đó xấu, nhưng thay vào đó làm hỏng chỉ số git của tôi.
Ciryon

13
Sử dụng điều này grep -r 'hello' -l --null . | xargs -0 sed -i 's#hello#world#g'để tránh chỉnh sửa các tệp không liên quan (sed có thể thay đổi mã hóa tệp).
caiguanhao 14/03/2015

6
"nhưng thay vào đó làm hỏng chỉ số git của tôi." Đừng quá lo lắng về điều này, bạn chỉ có thể làm find .git ... | ... 'sed -i s/(the opposite from before)/g'để sửa chỉ số git của mình
Massey101

259

Lưu ý : Không chạy lệnh này trên thư mục bao gồm repo git - thay đổi thành .git có thể làm hỏng chỉ số git của bạn.

find /home/www/ -type f -exec \
    sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +

So với các câu trả lời khác ở đây, điều này đơn giản hơn hầu hết và sử dụng sed thay vì perl, đó là những gì câu hỏi ban đầu yêu cầu.


50
Lưu ý rằng nếu bạn đang sử dụng BSD sed (bao gồm cả trên Mac OS X), bạn cần cung cấp một chuỗi rỗng rõ ràng cho -itùy chọn của sed . tức là: sed -i '' 's/original/replacement/g'
Nathan Craike

2
@JohnZwinck Sai lầm của tôi, đã bỏ lỡ +. Kỳ lạ thay, giải pháp của Nikita chạy nhanh hơn cho tôi.
Sam

6
@AoeAoe: Việc +giảm đáng kể số lượng sedquá trình sinh ra. Nó hiệu quả hơn.
John Zwinck

4
Làm thế nào tôi có thể làm điều này một cách an toàn trong một thư mục với một repo git?
Hatshepsut

20
Sẽ an toàn khi thực thi trên thư mục chứa repo git nếu bạn loại trừ repo khỏi kết quả tìm kiếm của bạn : find . -not -path '*/\.git*' -type f ....
Dale Anderson

210

Cách đơn giản nhất đối với tôi là

grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g'

1
@Anatoly: chỉ một câu hỏi: làm thế nào tôi có thể loại trừ các tệp nhị phân (tệp thực thi) ?
dùng2284570

3
@ user2284570 Sử dụng cờ -Ihoặc --binary-file=without-matchgrep.
Zéychin

34
Điều này đặc biệt tốt, khi bạn cần loại trừ các thư mục, như với .svn. Ví dụ:grep -rl oldtext . --exclude-dir=.svn | xargs sed -i 's/oldtext/newtext/g'
phyatt

11
brew install gnu-sedvà sử dụng gsedtrên OSX để tránh một thế giới đau đớn.
P i

1
Các bạn hãy chú ý, nếu dự án của bạn là phiên bản git, hãy sử dụng cái này thay thế : git grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g'. thật không hay chút nào để f * ck up .gitdir của bạn
Paolo

61

Tất cả các thủ thuật gần như giống nhau, nhưng tôi thích cái này:

find <mydir> -type f -exec sed -i 's/<string1>/<string2>/g' {} +
  • find <mydir>: tra cứu trong thư mục.

  • -type f:

    Tệp có loại: tệp thông thường

  • -exec command {} +:

    Biến thể của hành động -exec này chạy lệnh được chỉ định trên các tệp đã chọn, nhưng dòng lệnh được xây dựng bằng cách nối thêm từng tên tệp đã chọn ở cuối; tổng số lệnh gọi của lệnh sẽ ít hơn nhiều so với số lượng tệp được khớp. Dòng lệnh được xây dựng theo cách tương tự như xargs xây dựng các dòng lệnh của nó. Chỉ một trường hợp của `{} 'được cho phép trong lệnh. Lệnh được thực thi trong thư mục bắt đầu.


@ user2284570 với -exec? Cố gắng đặt đường dẫn để thực thi thay vì tên công cụ.
I159

@ I159: Không: loại trừ các tệp nhị phân thực thi (nhưng bao gồm các tập lệnh shell) .
dùng2284570

8
@ I159 Không phải câu trả lời này giống hệt với John Zwinck sao?
Phục hồi Monica Vui lòng

1
@ user2284570 Khái niệm "tệp nhị phân" không hoàn toàn được xác định rõ. Bạn có thể sử dụng filelệnh để cố gắng xác định từng loại tệp, nhưng các biến thể hỗn loạn trong đầu ra của nó có thể hơi hoang mang. Các -I(aka --mime) tùy chọn giúp phần nào, hoặc --mime-typenếu bạn có điều đó. Làm thế nào chính xác để cấu trúc lại lớp lót gọn gàng này để làm điều này thật đáng tiếc ngoài phạm vi cho hộp bình luận nhỏ này. Có thể gửi một câu hỏi riêng nếu bạn cần giúp đỡ? (Có thể thêm một nhận xét với một liên kết đến nó ở đây.)
tripleee

1
Câu trả lời rõ ràng nhất! cảm ơn bạn đời
jukerok

39
cd /home/www && find . -type f -print0 |
  xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'

2
Tôi tò mò, có lý do để sử dụng -print0xargsthay vì -exechay -execdirkhông?
Philipp

4
Có: từ "man find": Lệnh được chỉ định được chạy một lần cho mỗi tệp phù hợp. Đó là, nếu có 2000 tệp trong / home / www, thì 'find ... -exec ...' sẽ dẫn đến 2000 yêu cầu perl; trong khi 'tìm ... | xargs ... 'sẽ chỉ gọi perl một hoặc hai lần (giả sử ARG_MAX khoảng 32K và độ dài tên tệp trung bình là 20).
Sử dụng tiếng Nga

2
@Employed Russian: đó là lý do tại sao bạn sử dụng find -exec command {} +- nó tránh được các lệnh quá mức như xargs, nhưng không có quy trình riêng biệt.
John Zwinck

2
Trên nền tảng nào? Giải pháp xargs là di động, các yêu cầu "ma thuật" của "find ... -exec" không gọi ra một quy trình con cho mọi tệp được tìm thấy là không.
Sử dụng tiếng Nga

4
@EmployedRussian, find -exec ... {} +đã được POSIX chỉ định từ năm 2006.
Charles Duffy

34

Đối với tôi, giải pháp dễ nhớ nhất là https://stackoverflow.com/a/2113224/565525 , tức là:

sed -i '' -e 's/subdomainA/subdomainB/g' $(find /home/www/ -type f)

LƯU Ý : -i ''giải quyết vấn đề OSXsed: 1: "...": invalid command code .

LƯU Ý : Nếu có quá nhiều tệp để xử lý, bạn sẽ nhận được Argument list too long. Cách giải quyết - sử dụngfind -exec hoặc xargsgiải pháp được mô tả ở trên.


4
Các workaroundnên cú pháp ưa thích trong mọi trường hợp.
Phục hồi Monica Vui lòng

1
Vấn đề với sự thay thế lệnh $(find...)là không có cách nào để shell xử lý các tên tệp có khoảng trắng hoặc các siêu ký tự shell khác trong chúng. Nếu bạn biết đây không phải là một vấn đề, phương pháp này là tốt; nhưng chúng tôi có quá nhiều câu hỏi mà mọi người không cảnh báo về vấn đề này hoặc không hiểu cảnh báo.
tripleee

30

Đối với bất cứ ai sử dụng công cụ tìm kiếm bạc ( ag)

ag SearchString -l0 | xargs -0 sed -i 's/SearchString/Replacement/g'

Vì ag bỏ qua tệp / thư mục git / hg / svn theo mặc định, nên việc chạy bên trong kho lưu trữ là an toàn.


16

Một oneliner đẹp như là một phụ. Sử dụng git grep.

git grep -lz 'subdomainA.example.com' | xargs -0 perl -i'' -pE "s/subdomainA.example.com/subdomainB.example.com/g"

3
Ý tưởng tốt nếu làm việc bên trong repo git vì bạn không có nguy cơ ghi đè .git / nội dung (như đã báo cáo trong các nhận xét cho câu trả lời khác).
mahemoff

1
Cảm ơn, tôi sử dụng nó như một refactor() { echo "Replacing $1 by $2 in all files in this git repository." git grep -lz $1| xargs -0 perl -i'' -pE "s/$1/$2/g" }cách sử dụng chức năng bash , ví dụ để thay thế 'từ' bằng 'thanh kiếm': refactor word swordsau đó xác minh những gì nó đã làm với git diff.
Paul Rougieux

16

Để cắt giảm các tệp để đệ quy sedthông qua, bạn có thể grepcho ví dụ chuỗi của mình:

grep -rl <oldstring> /path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g

Nếu bạn chạy, man grepbạn sẽ nhận thấy rằng bạn cũng có thể xác định một --exlude-dir="*.git"cờ nếu bạn muốn bỏ qua tìm kiếm thông qua các thư mục .git, tránh các vấn đề về chỉ số git như những người khác đã chỉ ra một cách lịch sự.

Dẫn bạn đến:

grep -rl --exclude-dir="*.git" <oldstring> /path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g

13

Cái này tương thích với kho git, và đơn giản hơn một chút:

Linux:

git grep -l 'original_text' | xargs sed -i 's/original_text/new_text/g'

Mac:

git grep -l 'original_text' | xargs sed -i '' -e 's/original_text/new_text/g'

(Cảm ơn http://blog.jasonmeridth.com/posts/use-git-grep-to-replace-strings-in-files-in-your-git-reposeective/ )


Khôn ngoan hơn để sử dụng git-grep's -zlựa chọn cùng với xargs -0.
gniourf_gniourf

git greprõ ràng chỉ có ý nghĩa trong một gitrepo. Sự thay thế chung sẽ là grep -r.
tripleee

@gniourf_gniourf Bạn có thể giải thích?
Petr Peller

2
@PetrPeller: với -z, git-grepsẽ phân tách các trường đầu ra bằng byte rỗng thay vì dòng mới; và với -0, xargssẽ đọc đầu vào được phân tách bằng byte rỗng, thay vì khoảng trắng (và không làm những thứ lạ với dấu ngoặc kép). Vì vậy, nếu bạn không muốn lệnh bị hỏng nếu tên tệp chứa dấu cách, dấu ngoặc kép hoặc các ký tự vui nhộn khác, lệnh là : git grep -z -l 'original_text' | xargs -0 sed ....
gniourf_gniourf

10
find /home/www/ -type f -exec perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +

find /home/www/ -type f sẽ liệt kê tất cả các tệp trong / home / www / (và các thư mục con của nó). Cờ "-exec" cho biết find để chạy lệnh sau trên mỗi tệp được tìm thấy.

perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +

là lệnh chạy trên các tệp (nhiều lần). Được {}thay thế bằng tên tập tin. Phần +cuối của lệnh findsẽ tạo một lệnh cho nhiều tên tệp.

Trên findtrang man: "Dòng lệnh được xây dựng theo cách tương tự như xargs xây dựng các dòng lệnh của nó."

Do đó, có thể đạt được mục tiêu của bạn (và xử lý tên tệp có chứa khoảng trắng) mà không cần sử dụng xargs -0hoặc -print0.


8

Tôi chỉ cần điều này và không hài lòng với tốc độ của các ví dụ có sẵn. Vì vậy, tôi đã đưa ra ý tưởng của riêng mình:

cd /var/www && ack-grep -l --print0 subdomainA.example.com | xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'

Ack-grep rất hiệu quả trong việc tìm kiếm các tập tin liên quan. Lệnh này đã thay thế ~ 145 000 tệp một cách dễ dàng trong khi các lệnh khác mất quá nhiều thời gian tôi không thể đợi cho đến khi chúng hoàn thành.


Đẹp, nhưng grep -ril 'subdomainA' *không nơi nào nhanh như grep -Hr 'subdomainA' * | cut -d: -f1.
trusktr

@Henno: chỉ một câu hỏi: làm thế nào tôi có thể loại trừ các tệp nhị phân (tệp thực thi) ?
dùng2284570

ack-grep tự động làm điều đó cho bạn.
Henno

@Henno: Nó có bao gồm các kịch bản shell?
dùng2284570

Đúng. Dưới đây là danh sách đầy đủ các loại tệp mà nó hỗ trợ: beyondgrep.com/documentation
Henno

6

Phương thức chuyển tiếp thẳng nếu bạn cần loại trừ thư mục ( --exclude-dir=.svn) và cũng có thể có tên tệp có dấu cách (sử dụng 0Byte với grep -Zxargs -0

grep -rlZ oldtext . --exclude-dir=.svn | xargs -0 sed -i 's/oldtext/newtext/g'

5

grep -lr 'subdomainA.example.com' | while read file; do sed -i "s/subdomainA.example.com/subdomainB.example.com/g" "$file"; done

Tôi đoán hầu hết mọi người không biết rằng họ có thể chuyển một cái gì đó vào một "tập tin đang đọc" và nó tránh được những tranh luận -print0 khó chịu đó, trong khi đoán trước các khoảng trắng trong tên tệp.

Thêm một echotrước khi sed cho phép bạn xem những tập tin nào sẽ thay đổi trước khi thực sự làm điều đó.


Lý do -print0rất hữu ích là nó xử lý các trường hợp while readđơn giản là không thể xử lý - một dòng mới là một ký tự hợp lệ trong tên tệp Unix, do đó, để mã của bạn hoàn toàn mạnh mẽ, nó cũng cần phải đối phó với các tên tệp đó. (Ngoài ra, bạn muốn read -rtránh một số hành vi di sản POSIX read
phiền phức

Ngoài ra, sedkhông có gì phù hợp nếu không có trận đấu, vì vậy điều đó grepkhông thực sự cần thiết; mặc dù đó là một tối ưu hóa hữu ích để tránh viết lại các tệp không chứa bất kỳ kết quả khớp nào, nếu bạn có nhiều tệp đó hoặc muốn tránh cập nhật tem ngày trên các tệp một cách không cần thiết.
tripleee 18/2/2016

5

Bạn có thể sử dụng awk để giải quyết vấn đề này như dưới đây,

for file in `find /home/www -type f`
do
   awk '{gsub(/subdomainA.example.com/,"subdomainB.example.com"); print $0;}' $file > ./tempFile && mv ./tempFile $file;
done

Hy vọng điều này sẽ giúp bạn !!!


Hoạt động trên MacO không có vấn đề gì! Tất cả sedcác lệnh dựa trên đều thất bại khi các tệp nhị phân được đưa vào ngay cả với các cài đặt cụ thể của osx.
Jankapunkt

Cẩn thận ... điều này sẽ nổ tung nếu bất kỳ tệp nào findtrả về có một khoảng trắng trong tên của chúng! Sử dụng an toàn hơn nhiều while read: stackoverflow.com/a/9612560/1938956
Soren Bjornstad

5

Cách đơn giản nhất để thay thế ( tất cả các tệp, thư mục, đệ quy )

find . -type f -not -path '*/\.*' -exec sed -i 's/foo/bar/g' {} +

Lưu ý: Đôi khi bạn có thể cần phải bỏ qua một số tệp ẩn..git , bạn có thể sử dụng lệnh trên.

Nếu bạn muốn bao gồm các tập tin ẩn sử dụng,

find . -type f  -exec sed -i 's/foo/bar/g' {} +

Trong cả hai trường hợp, chuỗi foosẽ được thay thế bằng chuỗi mớibar


4

Thử cái này:

sed -i 's/subdomainA/subdomainB/g' `grep -ril 'subdomainA' *`

1
Xin chào @RikHic, mẹo hay - đã suy nghĩ về một cái gì đó như thế này; Thật không may là định dạng ở trên không hoàn toàn đúng :) Vì vậy, tôi sẽ thử với một thẻ trước (không hoạt động) - vì vậy với việc thoát backticks sau đó: sed -i 's/subdomainA/subdomainB/g'` grep -ril 'subdomainA' /home/www/*` - điều này vẫn không quá tốt, nhưng nên tồn tại bản sao :) Chúc mừng!
sdaau

4
#!/usr/local/bin/bash -x

find * /home/www -type f | while read files
do

sedtest=$(sed -n '/^/,/$/p' "${files}" | sed -n '/subdomainA/p')

    if [ "${sedtest}" ]
    then
    sed s'/subdomainA/subdomainB/'g "${files}" > "${files}".tmp
    mv "${files}".tmp "${files}"
    fi

done

4

Theo bài đăng trên blog này :

find . -type f | xargs perl -pi -e 's/oldtext/newtext/g;'

Làm thế nào để bạn thoát khỏi dấu gạch chéo /? Ví dụ: tôi muốn thay thế địa chỉ IP: xxx.xxx.xxx.xxxforxxx.xxx.xxx.xxx/folder
Pathros

Bạn có thể thoát /với \. Ví dụ:find . -type f | xargs perl -pi -e 's/xxx.xxx.xxx.xxx\/folder/newtext/g;'
J.Hpour 17/03/18

3

Nếu bạn không ngại sử dụng vimcùng với grephoặc findcác công cụ, bạn có thể theo dõi câu trả lời do người dùng Gert đưa ra trong liên kết này -> Làm cách nào để thay thế văn bản trong phân cấp thư mục lớn? .

Đây là thỏa thuận:

  • grep đệ quy cho chuỗi mà bạn muốn thay thế trong một đường dẫn nhất định và chỉ lấy đường dẫn hoàn chỉnh của tệp phù hợp. (đó sẽ là $(grep 'string' 'pathname' -Rl).

  • (tùy chọn) nếu bạn muốn tạo bản sao lưu trước các tệp đó trong thư mục tập trung, có lẽ bạn cũng có thể sử dụng tệp này: cp -iv $(grep 'string' 'pathname' -Rl) 'centralized-directory-pathname'

  • sau đó, bạn có thể chỉnh sửa / thay thế theo ý muốn vimtheo sơ đồ tương tự như sơ đồ được cung cấp trên liên kết đã cho:

    • :bufdo %s#string#replacement#gc | update

2

Một trường học hơi cũ nhưng điều này đã làm việc trên OS X.

Có một vài mánh khóe:

• Sẽ chỉ chỉnh sửa các tệp có phần mở rộng .slstrong thư mục hiện tại

.phải được thoát để đảm bảo sedkhông đánh giá chúng là "bất kỳ nhân vật nào"

,được sử dụng làm seddấu phân cách thay vì thông thường/

Cũng lưu ý điều này là để chỉnh sửa mẫu Jinja để vượt qua variabletrong đường dẫn của một import(nhưng đây không phải là chủ đề).

Đầu tiên, xác minh lệnh sed của bạn làm những gì bạn muốn (điều này sẽ chỉ in các thay đổi thành thiết bị xuất chuẩn, nó sẽ không thay đổi các tệp):

for file in $(find . -name *.sls -type f); do echo -e "\n$file: "; sed 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file; done

Chỉnh sửa lệnh sed khi cần thiết, khi bạn đã sẵn sàng thực hiện thay đổi:

for file in $(find . -name *.sls -type f); do echo -e "\n$file: "; sed -i '' 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file; done

Lưu ý -i ''trong sed lệnh , tôi không muốn tạo bản sao lưu của các tệp gốc (như được giải thích trong các chỉnh sửa tại chỗ với sed trên OS X hoặc trong nhận xét của Robert Lujo trong trang này).

Chúc mọi người an ủi!


2

chỉ để tránh thay đổi

  • Gần nhưsubdomainA.example.com
  • tên miền phụA.example.comp.other

nhưng vẫn

  • tên miền phụA.example.com.IsIt.good

(có thể không tốt trong ý tưởng đằng sau root domain)

find /home/www/ -type f -exec sed -i 's/\bsubdomainA\.example\.com\b/\1subdomainB.example.com\2/g' {} \;

2

Tôi chỉ sử dụng ngọn:

find . -name '*.[c|cc|cp|cpp|m|mm|h]' -print0 |  xargs -0 tops -verbose  replace "verify_noerr(<b args>)" with "__Verify_noErr(<args>)" \
replace "check(<b args>)" with "__Check(<args>)" 

cộng một cho `'*. [c | cc | cp | cpp | m | mm | h]'`
FractalSpace

2

Đây là một phiên bản nên chung chung hơn hầu hết; nó không yêu cầu find(sử dụng duthay thế), ví dụ. Nó không yêu cầu xargs, chỉ được tìm thấy trong một số phiên bản của Kế hoạch 9 (như 9front).

 du -a | awk -F' '  '{ print $2 }' | xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'

Nếu bạn muốn thêm các bộ lọc như tiện ích mở rộng tệp, hãy sử dụng grep:

 du -a | grep "\.scala$" | awk -F' '  '{ print $2 }' | xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'

1

Đối với Qshell (qsh) trên IBMi, không bash như được gắn thẻ bởi OP.

Hạn chế của lệnh qsh:

  • tìm không có tùy chọn -print0
  • xargs không có tùy chọn -0
  • sed không có tùy chọn -i

Do đó, giải pháp trong qsh:

    PATH='your/path/here'
    SEARCH=\'subdomainA.example.com\'
    REPLACE=\'subdomainB.example.com\'

    for file in $( find ${PATH} -P -type f ); do

            TEMP_FILE=${file}.${RANDOM}.temp_file

            if [ ! -e ${TEMP_FILE} ]; then
                    touch -C 819 ${TEMP_FILE}

                    sed -e 's/'$SEARCH'/'$REPLACE'/g' \
                    < ${file} > ${TEMP_FILE}

                    mv ${TEMP_FILE} ${file}
            fi
    done

Hãy cẩn thận:

  • Giải pháp không bao gồm xử lý lỗi
  • Không phải Bash như được gắn thẻ bởi OP

Điều này có một số vấn đề đáng tiếc với trích dẫn cũng như đọc các dòng với for.
tripleee

1

Nếu bạn muốn sử dụng điều này mà không phá hủy hoàn toàn kho lưu trữ SVN của mình, bạn có thể nói 'tìm' để bỏ qua tất cả các tệp bị ẩn bằng cách thực hiện:

find . \( ! -regex '.*/\..*' \) -type f -print0 | xargs -0 sed -i 's/subdomainA.example.com/subdomainB.example.com/g'

Các dấu ngoặc đơn dường như là thừa. Điều này trước đây có lỗi định dạng khiến nó không thể sử dụng được (kết xuất Markdown sẽ ăn một số ký tự từ regex).
tripleee

1

Sử dụng kết hợp grepsed

for pp in $(grep -Rl looking_for_string)
do
    sed -i 's/looking_for_string/something_other/g' "${pp}"
done

@tripleee Mình sửa cái này một chút. Trong trường hợp này, đầu ra cho lệnh grep -Rl patterntạo danh sách các tệp có mẫu. Các tập tin không được đọc trong forvòng lặp.
Pawel

Huh? Bạn vẫn có một forvòng lặp; nếu bất kỳ tên tệp được trả về nào chứa khoảng trắng, nó sẽ không hoạt động chính xác, vì shell sẽ mã hóa fordanh sách đối số. Nhưng sau đó, bạn sử dụng biến tên tệp mà không có dấu ngoặc kép bên trong vòng lặp, vì vậy nó sẽ bị hỏng ở đó nếu bạn sửa lỗi này. Sửa các lỗi còn lại này sẽ khiến bạn giống hệt với câu trả lời của @ MadMan2064.
tripleee

@tripleee vâng, đó là sự thật, tôi đã bỏ lỡ điều này.
Pawel

1

Để thay thế tất cả các lần xuất hiện trong kho git, bạn có thể sử dụng:

git ls-files -z | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'

Xem danh sách tập tin trong repo git địa phương? cho các tùy chọn khác để liệt kê tất cả các tệp trong một kho lưu trữ. Các -ztùy chọn yêu cầu git tách các tên tệp bằng một byte bằng 0, đảm bảo rằng xargs(với tùy chọn -0) có thể tách các tên tệp, ngay cả khi chúng có chứa khoảng trắng hoặc không có gì.


1
perl -p -i -e 's/oldthing/new_thingy/g' `grep -ril oldthing *`

1
Không sử dụng awk/ sed, nhưng perl là phổ biến (ngoại trừ nhúng / hệ thống chỉ với busybox).
pevik

1

để thay đổi nhiều tệp (và lưu bản sao lưu dưới dạng *.bak):

perl -p -i -e "s/\|/x/g" *

sẽ lấy tất cả các tệp trong thư mục và thay thế |bằng x được gọi là một miếng bánh Perl (dễ như một chiếc bánh)


Không đệ quy thông qua các thư mục mặc dù.
PKHunter

có thể dẫn đến nó, điều này làm cho nó rất dễ điều chỉnh, bao gồm cả thông qua các thư mục. josephscott.org/archives/2005/08/...unix.stackexchange.com/questions/101415/...
Stenemo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.