Ricerca ricorsiva e sostituzione in file di testo su Mac e Linux


127

Nella shell di linux, il seguente comando cercherà in modo ricorsivo e sostituirà tutte le istanze di 'this' con 'that' (non ho una shell Linux davanti a me, ma dovrebbe farlo).

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

Come sarà un comando simile su OSX?


Probabilmente dovrebbe essere spostato apple.stackexchange.comperché non è abbastanza generico per Linux né per tutti gli sviluppatori.
AlikElzin-Kilaka,

Risposte:


246

OS X utilizza un mix di strumenti BSD e GNU, quindi è meglio controllare sempre la documentazione (anche se l'ho avuto che lessnon era nemmeno conforme alla manpage di OS X):

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

sed prende l'argomento dopo -icome estensione per i backup. Fornire una stringa vuota ( -i '') per nessun backup.

Quanto segue dovrebbe fare:

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

Il -type fè solo buone pratiche; sed si lamenterà se gli dai una directory o giù di lì. -execè preferito sopra xargs; non devi preoccuparti di -print0niente o altro. Alla {} +fine significa che findaggiungerà tutti i risultati come argomenti a un'istanza del comando chiamato, invece di rieseguirlo per ogni risultato. (Un'eccezione è quando viene violato il numero massimo di argomenti della riga di comando consentiti dal sistema operativo; in tal caso findverrà eseguita più di un'istanza.)


2
Il mio "questo" in questa sostituzione contiene una barra (localhost / sito) - Sto sostituendo parti di un URL in un file .html .... come posso effettuare tale sostituzione. Ho provato a mettere tra virgolette, ma non ci riesce.
Timothy T.

6
Sintassi sed consente di utilizzare praticamente qualsiasi carattere al posto della barra, ad esempio, è possibile utilizzare il %carattere: sed "s%localhost/site%blah/blah%". Un'altra alternativa è quella di barra inversa sfuggire il separatore: sed "s/localhost\/site/blah\/blah/".
TaylanUB,

Grazie fammi provare. Ho comunque provato a usare {} per separare la barra e ho ancora un errore ...
Timothy T.

16
Qualcun altro sta ricevendo un illegal byte sequenceerrore? in tal caso, prova:, LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ {} +ha funzionato per me.
ColdTuna,

10
Questo sostituirà solo un ocurreny per file, utilizzare /gper più occasioni comeLC_ALL=C find . -type f -exec sed -i '' s/search/replace/g {} +
jamesjara,

152

Per il mac, un approccio più simile sarebbe questo:

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

10
Vorrei poter votare questo ogni volta che ci torno e lo uso. Ormai sarebbe a +15, facile.
Droogans,

Per qualche motivo, non funziona per me. Non fa niente. Sono nella cartella form360 e sto cercando di cambiare tutte le istanze di stringa con il nome easyform in form360, sto eseguendo il seguente comando:find . -name '*.php' -print0 | xargs -0 sed -i "" "s/easyform/form360/g"
Andres Ramos,

2
per me, questa dovrebbe essere la risposta corretta. È l'unico che ha funzionato per me.
nosequeldeebee,

1
-print0 | xargs -0 non funziona sul mio mac quando il nome del file contiene spazio.
user2807219

1
sed:.: la modifica sul posto funziona solo con file normali
codeslapper

14

Come soluzione alternativa, sto usando questo su Mac OSX 10.7.5

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

Il merito va a: la risposta di Todd Cesere


Questo funziona bene! Altri script aggiungono un ulteriore fine riga in alcuni casi su OSX! Molte grazie!
Sebastien Filion,

14

Su Mac OSX 10.11.5 funziona perfettamente:

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

xargs -I @ sed -i '' 's / old-word / new-word / g' @ ha funzionato per me dopo aver provato tanti altri suggerimenti non funzionanti. Grazie!
DrB il

13

Nessuna delle precedenti funzioni su OSX.

Eseguire le seguenti operazioni:

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

1
come scape '/' se SEARCH_FOR e REPLACE_WITH sono percorsi?
rraallvv

Utilizzare un delimitatore diverso. Se stai usando percorsi, due punti o pipe funzionerebbero. 's | SEARCH | REPLACE | g', ad esempio. Le nostre parentesi graffe di utilizzo, come in 's {SEARCH} {REPLACE}'.
dannysauer,

1
dito domanda, provandolo no su Mac - ma sembra generare un errore? Ad esempio, il mio percorso viene interpretato come un file? -bash: localhost / nohost: nessun file o directory simile
Timothy T.

questo non si verifica attraverso le cartelle in profondità. Solo un livello.
Sergey Romanov,

Per ulteriori informazioni su questo comando leggere questo lifehacker.com/5810026/...
kuzdu

7

Una versione che funziona su Linux e Mac OS X (aggiungendo l' -eopzione a sed):

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

Ho dovuto fare l'esportazione da questa risposta + la riga dalla risposta accettata (non volevo che i file di backup venissero generati)
Lance

2
per correggere l'errore "Sequenza di byte illegali", prova a impostare LOCALE prima di eseguire il comando: export LC_CTYPE=C && export LANG=C
cjoy

NON ESEGUIRE MAI questo con '*' invece di '* .filetype' come ho fatto se si utilizza Git. Oppure puoi dire addio a tutto il tuo lavoro inedito.
Sergey,

1
La versione mac del comando sed richiede un '' dopo il -i, quindi questa risposta non è corretta
G Huxley,

2

Ogni volta che scrivo questo comando, mi sembra sempre di intasarlo o di dimenticare una bandiera. Ho creato un Gist su github sulla base della risposta di TaylanUB che sostituisce una ricerca globale dalla directory corrente. Questo è specifico per Mac OSX.

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

È bello perché ora apro un terminale e poi copio:

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

È possibile ottenere alcuni strani errori di sequenza di byte, quindi ecco il codice completo:

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

Questo è il mio praticabile. su mac OS X 10.10.4

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

I precedenti usano find cambieranno i file che non contengono il testo di ricerca (aggiungi una nuova riga alla fine del file), che è dettagliata.


2

Se stai usando un terminale zsh, puoi usare la magia jolly:

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


1

Ho usato questo formato - ma ... ho scoperto che dovevo eseguirlo tre o più volte per farlo cambiare davvero ogni istanza che trovavo estremamente strana. Eseguirlo una volta cambierebbe alcuni in ogni file ma non in tutti. Eseguire esattamente la stessa stringa due o quattro volte catturerebbe tutte le istanze.

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

Avevi bisogno di eseguire questo comando più volte b / c alla tua sed regex galla fine, altrimenti sostituisce solo la prima occorrenza di thistextuna riga. Quindi il tuo regex dovrebbe esseres/thistext/newtext/g
Les Nightingill

0

https://bitbucket.org/masonicboom/serp è un'utilità go (ovvero multipiattaforma), testata su OSX, che effettua ricorsivi ricerca e sostituzione di testo nei file all'interno di una determinata directory e conferma ogni sostituzione. È nuovo, quindi potrebbe essere difettoso.

L'utilizzo è simile a:

$ 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

0
find . -type f | xargs sed -i '' 's/string1/string2/g'

Fare riferimento qui per maggiori informazioni.


-3

Il comando su OSX dovrebbe essere esattamente lo stesso di Unix nella graziosa UI.


Ho pensato tanto, ma no. Mette un ./ davanti ai file quando si alimenta a sed, quindi sed si lamenta "codice di comando non valido". Forse sono solo stanco ;-)
Jack

@JacobusR, per favore taglia e incolla dal tuo terminale OSX - devi inserire qualcosa di leggermente diverso.
Glenn Jackman,

3
È possibile che si desideri -print0aggiungere alle findbandiere e -0alle xargsbandiere.
jmtd

Puoi anche usare e -exec sed -i s/this/that/g {} \+invece di -printe xargs
Marian

@JacobusR - funziona, anche se c'è un percorso principale './'. Tuttavia, se c'è uno spazio nel nome del file, dire "./jacobus \ R.txt", l'uso di xargspotrebbe vedere lo spazio delimitato "./jacobus" come un file a cui passare sed, quindi con "R.txt" , nessuno dei quali esiste.
Brett Hale

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.