Tìm kiếm đệ quy và thay thế trong các tệp văn bản trên Mac và Linux


127

Trong shell linux, lệnh sau sẽ tìm kiếm đệ quy và thay thế tất cả các phiên bản của 'this' bằng 'that' (Tôi không có shell Linux trước mặt tôi, nhưng nó nên làm).

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

Lệnh tương tự trên OSX sẽ như thế nào?


Có lẽ nên chuyển sang apple.stackexchange.comvì nó không đủ chung cho linux cũng như tất cả các nhà phát triển.
AlikElzin-kilaka

Câu trả lời:


246

OS X sử dụng kết hợp các công cụ BSD và GNU, vì vậy tốt nhất là luôn kiểm tra tài liệu (mặc dù tôi đã có nó lessthậm chí không phù hợp với trang web của OS X):

https://web.archive.org/web/20170808213955/https://developer.apple.com/legacy/l Library / documentation / Darwin / Reference / Manager / man1 / sed.1.html

sed lấy đối số sau -ilàm phần mở rộng cho các bản sao lưu. Cung cấp một chuỗi rỗng ( -i '') để không sao lưu.

Sau đây nên làm:

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

Đây -type fchỉ là thực hành tốt; sed sẽ phàn nàn nếu bạn cho nó một thư mục. -execđược ưa thích hơn xargs; bạn không cần bận tâm với -print0bất cứ điều gì. Các {} +tại các phương tiện kết thúc mà findsẽ nối tất cả kết quả như các đối số cho một ví dụ của lệnh gọi, thay vì tái chạy nó cho mỗi kết quả. (Một ngoại lệ là khi số lượng đối số dòng lệnh tối đa được HĐH cho phép bị vi phạm; trong trường hợp đó findsẽ chạy nhiều hơn một phiên bản.)


2
"Cái này" trong thay thế này chứa một dấu gạch chéo (localhost / site) - Tôi đang thay thế các phần của URL trong tệp .html .... làm cách nào để thay thế như vậy. Tôi đã thử đặt dấu ngoặc kép, nhưng không thành công.
Timothy T.

6
Cú pháp sed cho phép sử dụng hầu hết mọi ký tự thay cho dấu gạch chéo, ví dụ: bạn có thể sử dụng %ký tự : sed "s%localhost/site%blah/blah%". Một cách khác là dấu gạch chéo ngược - thoát khỏi dấu phân cách : sed "s/localhost\/site/blah\/blah/".
TaylanUB

Cảm ơn bạn cho tôi thử điều đó. Tuy nhiên, tôi đã thử sử dụng {} để phân tách dấu gạch chéo và tôi vẫn gặp lỗi ...
Timothy T.

16
Bất cứ ai khác nhận được illegal byte sequencelỗi? Nếu vậy, hãy thử : LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ {} +, nó làm việc cho tôi.
ColdTuna

10
Điều này sẽ chỉ thay thế một ocurreny cho mỗi tệp, sử dụng /gcho nhiều số lần nhưLC_ALL=C find . -type f -exec sed -i '' s/search/replace/g {} +
jamesjara

152

Đối với mac, một cách tiếp cận tương tự hơn sẽ là:

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

10
Tôi ước tôi có thể nâng cao điều này mỗi khi tôi quay lại và sử dụng nó. Bây giờ là +15 rồi, dễ thôi.
Giọt nước

Vì một số lý do, nó không hoạt động với tôi. Nó không làm gì cả. Tôi đang ở trong thư mục form360 và tôi đang cố gắng thay đổi tất cả các trường hợp chuỗi với tên easyform thành form360, tôi dùng một lệnh sau:find . -name '*.php' -print0 | xargs -0 sed -i "" "s/easyform/form360/g"
Andres Ramos

2
Đối với tôi, đây là câu trả lời đúng. Đó là người duy nhất làm việc cho tôi.
Nosequeldeebee

1
-print0 | xargs -0 không hoạt động trên máy mac của tôi khi tên tệp chứa không gian.
user2807219

1
sed:.: chỉnh sửa tại chỗ chỉ hoạt động đối với các tệp thông thường
Codelapper

14

Là một giải pháp thay thế, tôi đang sử dụng giải pháp này trên Mac OSX 10.7.5

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

Tín dụng đi đến: câu trả lời của Todd Cesere


Cái này hoạt động tốt! Các tập lệnh khác thêm một đầu cuối của dòng trong một số trường hợp trên OSX! Cảm ơn rất nhiều!
Sebastien Filion

14

Trên Mac OSX 10.11.5, nó hoạt động tốt:

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

xargs -I @ sed -i '' s / old-word / new-word / g '@ đã làm việc cho tôi sau khi thử rất nhiều đề xuất không hoạt động khác. Cảm ơn bạn!
DrB

13

Không có điều nào ở trên hoạt động trên OSX.

Làm như sau:

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

1
làm thế nào để scape '/' nếu SEARCH_FOR và REPLACE_WITH là đường dẫn?
rraallvv

Sử dụng một dấu phân cách khác nhau. Nếu bạn đang sử dụng đường dẫn, dấu hai chấm hoặc đường ống sẽ hoạt động. Chẳng hạn như | TÌM KIẾM | THAY THẾ | g '. Chúng tôi sử dụng niềng răng, như trong {SEARCH} {REPLACE} '.
dannysauer

1
câu hỏi dito, thử nó không có trên Mac - nhưng dường như nó tạo ra một lỗi? Ví dụ, đường dẫn của tôi được hiểu là một tập tin? -bash: localhost / nohost: Không có tệp hoặc thư mục như vậy
Timothy T.

Điều này không tái diễn qua các thư mục sâu. Chỉ có một cấp độ.
Sergei Romanov

Để biết thêm thông tin về lệnh này, hãy đọc lifehacker.com/5810026/
Kẻ

7

Phiên bản hoạt động trên cả Linux và Mac OS X (bằng cách thêm công -etắc vào sed):

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

Tôi đã phải thực hiện xuất từ ​​câu trả lời này + dòng từ câu trả lời được chấp nhận (tôi không muốn tạo tệp sao lưu)
Lance

2
để khắc phục lỗi 'chuỗi byte bất hợp pháp', hãy thử đặt LOCALE trước khi chạy lệnh: export LC_CTYPE=C && export LANG=C
cjoy

KHÔNG ĐƯỢC CHẠY cái này với '*' thay vì '* .filetype' như tôi đã làm nếu bạn đang sử dụng Git. Hoặc bạn có thể nói lời tạm biệt với tất cả các công việc chưa được công bố của bạn.
Sergey

1
Phiên bản mac của lệnh sed yêu cầu '' sau -i, vì vậy câu trả lời này không chính xác
G Huxley

2

Bất cứ khi nào tôi gõ lệnh này, tôi dường như luôn hất nó lên hoặc quên một lá cờ. Tôi đã tạo một Gist trên github dựa trên câu trả lời của TaylanUB, một công cụ tìm kiếm toàn cầu thay thế từ thư mục hiện tại. Đây là Mac OSX cụ thể.

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

Thật tuyệt vì bây giờ tôi chỉ cần mở một thiết bị đầu cuối rồi sao chép vào:

curl -s https://gist.github.com/nateflink/9056302/raw/findreplaceosx.sh | bash -s "find-a-url.com" "thay-a-url.com"

Bạn có thể nhận được một số lỗi chuỗi byte kỳ lạ, vì vậy đây là mã đầy đủ:

#!/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

Đây là một trong những công việc của tôi. trên mac OS X 10.10.4

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

Những cái ở trên sử dụng find sẽ thay đổi các tệp không chứa văn bản tìm kiếm (thêm một dòng mới ở cuối tệp), đó là dài dòng.


2

Nếu bạn đang sử dụng thiết bị đầu cuối zsh, bạn có thể sử dụng phép thuật ký tự đại diện:

sed -i "" "s/search/high-replace/g" *.txt


1

Tôi đã sử dụng định dạng này - nhưng ... tôi thấy tôi phải chạy nó ba lần trở lên để thực sự thay đổi mọi trường hợp mà tôi thấy vô cùng kỳ lạ. Chạy nó một lần sẽ thay đổi một số trong mỗi tệp nhưng không phải tất cả. Chạy chính xác cùng một chuỗi hai bốn lần sẽ bắt được tất cả các trường hợp.

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

Bạn cần chạy lệnh này nhiều lần b / c, regex sed của bạn cần một gdấu chấm ở cuối, nếu không nó chỉ thay thế lần xuất hiện đầu tiên của thistextmột dòng. Vì vậy, regex của bạn nên làs/thistext/newtext/g
Les Nightingill

0

https://bitbucket.org/masonicboom/serp là một tiện ích đi (nghĩa là đa nền tảng), đã được thử nghiệm trên OSX, tìm kiếm đệ quy và thay thế văn bản trong các tệp trong một thư mục nhất định và xác nhận từng thay thế. Nó mới, vì vậy có thể có lỗi.

Cách sử dụng trông như:

$ 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

Lệnh trên OSX phải giống hệt như Unix trong giao diện người dùng đẹp.


Tôi nghĩ nhiều như vậy, nhưng không. Nó đặt một ./ trước các tập tin khi nạp vào sed, vì vậy sed phàn nàn 'mã lệnh không hợp lệ'. Có lẽ tôi chỉ mệt thôi ;-)
Jack

@JacobusR, vui lòng cắt và dán từ thiết bị đầu cuối OSX của bạn - bạn phải nhập một cái gì đó hơi khác.
glenn jackman

3
Bạn có thể muốn -print0thêm vào findlá cờ và -0đến xargscờ.
jmtd

Bạn cũng có thể chỉ sử dụng -exec sed -i s/this/that/g {} \+thay vì -printvà xargs
Marian

@JacobusR - điều này hoạt động, ngay cả khi có tên đường dẫn './' hàng đầu. Tuy nhiên, nếu có một khoảng trắng trong tên tệp, hãy nói "./jacobus \ R.txt", việc sử dụng xargscó thể thấy "./jacobus" được phân cách bằng dấu cách sedvà sau đó với "R.txt" , không ai trong số đó tồn tại.
Brett Hale

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.