comando sed con l'opzione -i non riuscita su Mac, ma funziona su Linux


303

Ho usato con successo il seguente sedcomando per cercare / sostituire il testo in Linux:

sed -i 's/old_link/new_link/g' *

Tuttavia, quando lo provo sul mio Mac OS X, ottengo:

"il comando c prevede \ seguito dal testo"

Pensavo che il mio Mac avesse una normale shell BASH. Che cosa succede?

MODIFICARE:

Secondo @High Performance, ciò è dovuto al fatto che il Mac ha sedun sapore diverso (BSD), quindi la mia domanda sarebbe quindi come posso replicare questo comando in BSD sed?

MODIFICARE:

Ecco un esempio reale che causa questo:

sed -i 's/hello/gbye/g' *

1
Ciò significa che sedvede una "c" nei tuoi dati come comando. Stai usando una variabile? Pubblica qualcosa che rappresenti più da vicino il comando effettivo e alcuni dati che stai elaborando. Puoi ottenere una semplice dimostrazione di questo errore facendo echo x | sed c.
In pausa fino a ulteriore avviso.

@Dennis, il semplice comando sopra riportato causa questo, sebbene i dati che sta elaborando siano un intero sito Web (sto convertendo tutti i collegamenti di immagini), inclusi i file html e css ...
Yarin,

Risposte:


397

Se si utilizza l' -iopzione, è necessario fornire un'estensione per i backup.

Se hai:

File1.txt
File2.cfg

Il comando (nota la mancanza di spazio tra -ie ''e il -eper farlo funzionare su nuove versioni di Mac e su GNU):

sed -i'.original' -e 's/old_link/new_link/g' *

Crea 2 file di backup come:

File1.txt.original
File2.cfg.original

Non esiste un modo portatile per evitare di creare file di backup perché è impossibile trovare un mix di comandi sed che funzioni su tutti i casi:

  • sed -i -e ...- non funziona su OS X in quanto crea -ebackup
  • sed -i'' -e ... - non funziona su OS X 10.6 ma funziona su 10.9+
  • sed -i '' -e ... - non funziona su GNU

Nota Dato che non esiste un comando sed su tutte le piattaforme, è possibile provare a utilizzare un altro comando per ottenere lo stesso risultato.

Per esempio, perl -i -pe's/old_link/new_link/g' *


4
Ho avuto lo stesso problema. Grazie per questa soluzione Ma dove ho provato con 'man sed' a trovare la descrizione di '-i', non c'è nulla sull'uso di -i '' per ignorare i backup. Questa è la mia prima colpa. In secondo luogo, quando viene visualizzato l'errore "comando prevede \ seguito dal testo", perché non ci dice direttamente che si aspetta un nome di backup per l'opzione '-i' !! ?? Una cosa del genere accade ovunque: si ottiene un errore ma non il motivo dell'errore, quindi si cerca il manuale che non spiega nulla al riguardo. Quindi vai su Google per trovare qualcun altro ha lo stesso problema. Voglio dire, perché non dare l'esempio nel manuale?
lukmac,

o dicci perché l'errore è presente anziché solo un messaggio senza informazioni sul verificarsi di un errore. Questo è un suggerimento per tutti i produttori di utensili, se possono mai leggere questo commento.
lukmac,

5
@lukmac Per quanto ne sedso, hai fornito un suffisso di backup. Il suffisso di backup è s/old_link/new_link/g. L'argomento successivo dovrebbe essere quello dei comandi di modifica. Poiché interpretava i comandi come nome di backup, prendeva quindi il primo nome file come comandi di modifica, ma non erano validi.
Barmar,

2
Sarà sempre un problema? C'è un modo in cui Apple potrebbe essere in grado di creare una soluzione alternativa / pacchetto GNU sed con OSX? Oppure GNU non è in grado di supportare sed -i '' -e ...?
blong

5
sed -i'' -esembra non funzionare come previsto su mac 10.14
MoOx il

64

Credo su OS X quando si utilizza -i è richiesta un'estensione per i file di backup . Provare:

sed -i .bak 's/hello/gbye/g' *

Utilizzando GNU sedl'estensione è facoltativa .


55

Funziona con entrambe le versioni GNU e BSD di sed:

sed -i'' -e 's/old_link/new_link/g' *

o con backup:

sed -i'.bak' -e 's/old_link/new_link/g' *

Nota spazio mancante dopo l' -iopzione! (Necessario per GNU sed)


7
Il primo non funziona su OSX (l'ho appena testato il 10.6.8)
marcin l'

4
Per me su OS X (10.10.3), il primo ha creato i file di backup con il suffisso -e. Non buono. La seconda è stata l'unica cosa che ha funzionato per me in modo coerente tra Ubuntu e OS X. Tuttavia, non volevo i file di backup, quindi ho dovuto eseguire un rmcomando subito dopo per eliminarlo.
Brendan,

1
La prima riga dovrebbe essere riscritta con uno spazio su cui lavorare il 10.10: sed -i'' ...=>sed -i '' ...
Daniel Jomphe,

3
@DanielJomphe Ma l'aggiunta di questo spazio non funziona su GNU sed
Brice,

1
@marcin per primo funziona anche su OSX 10.11.2. L'unica cosa è che crea un file di backup, che deve essere rimosso in seguito. Il secondo sembra migliore, dato che non dobbiamo capire il nome del file in seguito.
vikas027,

41

Ha avuto lo stesso problema in Mac e risolto con brew:

brew install gnu-sed

e usa come

gsed SED_COMMAND

puoi anche impostare sedcome alias su gsed(se vuoi):

alias sed=gsed

3
Perché hai dato esattamente la stessa risposta di Ohad Kravchick ?
gniourf_gniourf

1
impostare alias come questo non è una grande idea
SantaXL

1
Invece di un alias, come raccomandato nella pagina della birra corrispondente, aggiungilo al percorso: PATH = "$ (brew --prefix) / opt / gnu-sed / libexec / gnubin: $ PATH"
y.luis

24

Oppure puoi installare la versione GNU di sed sul tuo Mac, chiamata gsed, e usarla usando la sintassi standard di Linux.

Per questo, installa gsedusando le porte (se non lo hai, scaricalo su http://www.macports.org/ ) eseguendo sudo port install gsed. Quindi, puoi correresed -i 's/old_link/new_link/g' *


24
.. o se usi l'homebrew, installagnu-sed
Sudar il

1
Grazie @Sudar, doppio pollice in su!
Andrew Swan,

9

Il tuo Mac esegue effettivamente una shell BASH, ma questa è più una questione di quale implementazione di sed stai trattando. Su un Mac sed viene da BSD ed è leggermente diverso da quello che potresti trovare su un tipico box Linux. Ti consiglio man sed.


3
Grazie per aver sottolineato il problema di BSD- Ma sono abbastanza seducente e ho solo bisogno di una soluzione rapida per il mio
comando- Uno

5
@Yarin - no, e se do una rapida occhiata a man sed, anche questo non ti dice nulla. Prova uno sguardo più lungo.
High Performance Mark

21
La maggior parte delle risposte SO sono sepolte da qualche parte in un uomo, ma questo è ciò che SO è per le persone impegnate che hanno bisogno di risposte da persone intelligenti
Yarin,

9

La risposta di Sinetris è giusta, ma io uso questo con il findcomando per essere più specifico su quali file voglio cambiare. In generale questo dovrebbe funzionare (testato su osx /bin/bash):

find . -name "*.smth" -exec sed -i '' 's/text1/text2/g' {} \;

In generale, quando si utilizza sedsenza findprogetti complessi è meno efficiente.


-execè molto carino! Mi chiedo solo se il taglio alla fine sia effettivamente necessario
Ye Liu,

2
@YeLiu: senza il \, ;sono stato interpretato dalla shell quando l'ho provato
serv-inc

2

Ho creato una funzione per gestire la seddifferenza tra MacOS (testato su MacOS 10.12) e altri sistemi operativi:

OS=`uname`
# $(replace_in_file pattern file)
function replace_in_file() {
    if [ "$OS" = 'Darwin' ]; then
        # for MacOS
        sed -i '' -e "$1" "$2"
    else
        # for Linux and Windows
        sed -i'' -e "$1" "$2"
    fi
}

Uso:

$(replace_in_file 's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"',' "./mysql/.env")

Dove:

, è un delimitatore

's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"',' è modello

"./mysql/.env" è il percorso del file


1

Ecco come applicare le variabili di ambiente al file modello (non è necessario il backup).

1. Creare un modello con {{FOO}} per la successiva sostituzione.

echo "Hello {{FOO}}" > foo.conf.tmpl

2. Sostituire {{FOO}} con la variabile FOO e inviarlo al nuovo file foo.conf

FOO="world" && sed -e "s/{{FOO}}/$FOO/g" foo.conf.tmpl > foo.conf

Funziona sia con macOS 10.12.4 che con Ubuntu 14.04.5


0

Come indicano le altre risposte, non è possibile utilizzare sed in modo portabile su OS X e Linux senza creare file di backup. Quindi, invece, ho usato questo one-liner Ruby per farlo:

ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml

Nel mio caso, avevo bisogno di chiamarlo da rakeun'attività (cioè, all'interno di uno script Ruby), quindi ho usato questo ulteriore livello di quotazione:

sh %q{ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml}

-1
sed -ie 's/old_link/new_link/g' *

Funziona su BSD e Linux


3
Questo crea su Linux un altro nome file con l' eaggiunta
Brice

1
Rotto, meglio rimuoverlo.
Sorin,

Funziona su Mac e Linux. Qual è il problema con questa soluzione?
Islam Azab

No, non funziona su Mac BSD Sed: creerebbe un file di backup con "e" aggiunto al nome file.
Jesper Grann Laursen,
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.