Pencarian rekursif dan ganti dalam file teks pada Mac dan Linux

127

Di shell linux, perintah berikut ini akan secara rekursif mencari dan mengganti semua instance 'this' dengan 'that' (saya tidak memiliki shell Linux di depan saya, tetapi harus dilakukan).

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

Seperti apakah perintah yang serupa pada OSX?

Mendongkrak
sumber
Mungkin harus pindah ke apple.stackexchange.comkarena tidak cukup umum untuk linux atau semua pengembang.
AlikElzin-kilaka

Jawaban:

246

OS X menggunakan campuran alat BSD dan GNU, jadi sebaiknya selalu periksa dokumentasi (meskipun saya memilikinya yang lessbahkan tidak sesuai dengan manual OS X):

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

sed mengambil argumen setelah -isebagai ekstensi untuk cadangan. Berikan string kosong ( -i '') tanpa cadangan.

Yang berikut harus dilakukan:

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

Ini -type fhanya praktik yang baik; sed akan mengeluh jika Anda memberikannya direktori atau lebih. -execlebih disukai daripada xargs; Anda tidak perlu repot dengan -print0atau apapun. The {} +di bagian akhir berarti bahwa findakan menambahkan semua hasil sebagai argumen untuk satu instance dari perintah yang dipanggil, alih-alih menjalankannya kembali untuk setiap hasil. (Satu pengecualian adalah ketika jumlah maksimal argumen baris perintah yang diizinkan oleh OS dilanggar; dalam hal ini findakan menjalankan lebih dari satu contoh.)

TaylanUB
sumber
2
"Ini" saya di subtitusi ini berisi garis miring (localhost / situs) - Saya mengganti bagian-bagian dari URL dalam file .html .... bagaimana cara membuat subtitusi seperti itu. Saya mencoba memasukkan tanda kutip ganda, tetapi gagal.
Timothy T.
6
Sed sintaks memungkinkan menggunakan hampir setiap karakter di tempat slash, misalnya Anda bisa menggunakan %karakter: sed "s%localhost/site%blah/blah%". Alternatif lain adalah dengan backslash-melarikan diri pemisah: sed "s/localhost\/site/blah\/blah/".
TaylanUB
Terima kasih izinkan saya mencobanya. Namun saya mencoba menggunakan {} untuk memisahkan garis miring dan saya masih mendapatkan kesalahan ...
Timothy T.
16
Adakah yang mendapat illegal byte sequencekesalahan? jika demikian, coba LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ {} +:, itu berhasil untuk saya.
ColdTuna
10
Ini akan menggantikan hanya satu ocurreny per file, gunakan /guntuk beberapa ocurrency sepertiLC_ALL=C find . -type f -exec sed -i '' s/search/replace/g {} +
jamesjara
152

Untuk mac, pendekatan yang lebih mirip adalah ini:

find . -name '*.txt' -print0 | xargs -0 sed -i "" "s/form/forms/g"
Guybrush Threepwood
sumber
10
Saya berharap saya dapat memperbaiki ini setiap kali saya kembali dan menggunakannya. Sekarang jam +15, mudah.
Droogans
Untuk beberapa alasan, itu tidak berhasil untuk saya. Tidak melakukan apa-apa. Saya berada di dalam folder form360 dan saya mencoba mengubah semua instance string dengan nama easyform ke form360, saya menjalankan perintah berikut:find . -name '*.php' -print0 | xargs -0 sed -i "" "s/easyform/form360/g"
Andres Ramos
2
bagi saya, ini jawaban yang benar. Ini satu-satunya yang bekerja untuk saya.
nosequeldeebee
1
-print0 | xargs -0 tidak berfungsi pada mac saya ketika nama file berisi spasi.
user2807219
1
sed:.: pengeditan di tempat hanya berfungsi untuk file biasa
codeslapper
14

Sebagai solusi alternatif, saya menggunakan yang ini di Mac OSX 10.7.5

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

Kredit pergi ke: jawaban Todd Cesere ini

Maciej Gurban
sumber
Yang ini berfungsi dengan baik! Skrip lain menambahkan garis akhir tambahan dalam beberapa kasus di OSX! Terima kasih banyak!
Sebastien Filion
14

Pada Mac OSX 10.11.5 ini berfungsi dengan baik:

grep -rli 'old-word' * | xargs -I@ sed -i '' 's/old-word/new-word/g' @
madx
sumber
xargs -I @ sed -i '' s / old-word / new-word / g '@ bekerja untuk saya setelah mencoba begitu banyak saran tidak berfungsi lainnya. Terima kasih!
DrB
13

Tidak satu pun di atas berfungsi di OSX.

Lakukan hal berikut:

perl -pi -w -e 's/SEARCH_FOR/REPLACE_WITH/g;' *.txt
eb80
sumber
1
cara mencetak '/' jika SEARCH_FOR dan REPLACE_WITH adalah jalur?
rraallvv
Gunakan pembatas yang berbeda. Jika Anda menggunakan jalur, titik dua atau pipa akan berfungsi. 's | SEARCH | REPLACE | g', misalnya. Penggunaan kami menguatkan, seperti dalam {SEARCH} {REPLACE} '.
dannysauer
1
pertanyaan dito, mencoba tidak di Mac - tetapi tampaknya menghasilkan kesalahan? Misalnya, jalur saya ditafsirkan sebagai file? -bash: localhost / nohost: Tidak ada file atau direktori seperti itu
Timothy T.
ini tidak berulang melalui folder yang mendalam. Hanya satu level.
Sergey Romanov
Untuk info lebih lanjut tentang perintah ini, baca lifehacker.com/5810026/...
kuzdu
7

Versi yang berfungsi di Linux dan Mac OS X (dengan menambahkan -esakelar ke sed):

export LC_CTYPE=C LANG=C
find . -name '*.txt' -print0 | xargs -0 sed -i -e 's/this/that/g'
vroc
sumber
Saya harus melakukan ekspor dari jawaban ini + baris dari jawaban yang diterima (saya tidak ingin file cadangan dihasilkan)
Lance
2
untuk mengatasi kesalahan 'urutan byte ilegal', coba atur LOCALE sebelum menjalankan perintah: export LC_CTYPE=C && export LANG=C
cjoy
JANGAN PERNAH LARI ini dengan '*' alih-alih '* .filetype' seperti yang saya lakukan jika Anda menggunakan Git. Atau Anda bisa mengucapkan selamat tinggal pada semua karya yang tidak dipublikasikan.
Sergey
1
Versi mac dari perintah sed membutuhkan '' setelah -i, jadi jawaban ini salah
G Huxley
2

Setiap kali saya mengetik perintah ini, saya sepertinya selalu menyumbatnya, atau lupa bendera. Saya membuat Gist di github berdasarkan dari jawaban TaylanUB yang menggantikan global find dari direktori saat ini. Ini spesifik untuk Mac OSX.

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

Sangat menyenangkan karena sekarang saya hanya membuka terminal kemudian menyalin:

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

Anda bisa mendapatkan beberapa kesalahan urutan byte aneh, jadi di sini adalah kode lengkap:

#!/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
Nate Flink
sumber
2

Ini yang bisa saya kerjakan. pada mac OS X 10.10.4

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

Yang menggunakan find di atas akan mengubah file yang tidak mengandung teks pencarian (tambahkan baris baru di ujung file), yang verbose.

NoteCode
sumber
2

Jika Anda menggunakan terminal zsh Anda dapat menggunakan wildcard magic:

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

Mentor
sumber
1

Saya menggunakan format ini - tapi ... Saya menemukan saya harus menjalankannya tiga kali atau lebih untuk membuatnya benar-benar mengubah setiap contoh yang saya temukan sangat aneh. Menjalankannya sekali akan mengubah beberapa di setiap file tetapi tidak semua. Menjalankan string yang persis sama dua-empat kali akan menangkap semua instance.

find . -type f -name '*.txt' -exec sed -i '' s/thistext/newtext/ {} +
Emma
sumber
Anda perlu menjalankan perintah ini beberapa kali b / c Anda membutuhkan regex gdi akhir, jika tidak, itu hanya menggantikan kemunculan pertama thistextdalam sebuah baris. Jadi regex Anda seharusnyas/thistext/newtext/g
Les Nightingill
0

https://bitbucket.org/masonicboom/serp adalah utilitas go (yaitu lintas platform), diuji pada OSX, yang melakukan pencarian dan ganti rekursif untuk teks dalam file dalam direktori yang diberikan, dan mengonfirmasi setiap penggantian. Ini baru, jadi mungkin buggy.

Penggunaannya terlihat seperti:

$ 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
pengguna4425237
sumber
0
find . -type f | xargs sed -i '' 's/string1/string2/g'

Lihat di sini untuk info lebih lanjut.

pengguna2725109
sumber
-3

Perintah pada OSX harus persis sama dengan Unix di bawah UI cantik.

Clops
sumber
Saya banyak berpikir, tetapi tidak. Itu menempatkan ./ di depan file saat mengumpankan ke sed, jadi sed mengeluh 'kode perintah tidak valid'. Mungkin aku hanya lelah ;-)
Jack
@ JacobusR, silakan potong dan tempel dari terminal OSX Anda - Anda harus memasukkan sesuatu yang sedikit berbeda.
glenn jackman
3
Anda mungkin ingin -print0menambahkan ke findbendera dan -0ke xargsbendera.
jmtd
Anda juga bisa menggunakan dan -exec sed -i s/this/that/g {} \+bukannya -printxargs
Marian
@ JacobusR - ini berfungsi, bahkan jika ada nama path './' terkemuka. Namun, jika ada spasi dalam nama file, katakan "./jacobus \ R.txt", penggunaan xargsmungkin melihat spasi-dibatasi "./jacobus" sebagai file untuk diteruskan sed, dan kemudian dengan "R.txt" , tidak ada yang ada.
Brett Hale
-4

bisa saja mengatakan $ PWD bukannya "."

Samuel Devlin
sumber