2010-11-09 15 views
24

Per grep esiste un'opzione di stringa fissa, -F (fgrep) per disattivare l'interpretazione regolare della stringa di ricerca. C'è una struttura simile per sed? Non ho trovato nulla nell'uomo. Anche una raccomandazione di un altro strumento gnu/linux andrebbe bene.sed o simile: non interpretare come regex, interpretare come stringa fissa/letterale

sto usando sed per la ricerca e sostituzione funzionalità: sed -i "s/abc/def/g"

+0

possibile duplicato di [Fuga una stringa per modello di ricerca sed] (http://stackoverflow.com/questions/407523/escape-a-string-for-sed-search-pattern) –

risposta

5

Si deve usare replace invece di sed.

Dalla pagina man:

The replace utility program changes strings in place in files or on the 
    standard input. 

    Invoke replace in one of the following ways: 

     shell> replace from to [from to] ... -- file_name [file_name] ... 
     shell> replace from to [from to] ... < file_name 

    from represents a string to look for and to represents its replacement. 
    There can be one or more pairs of strings. 
+5

hmmm, non è stato installato "replace" - sembra uno strumento correlato a MySQL? Ho installato MySql; c'è un'installazione separata da sostituire? – EoghanM

+0

Non viene in un pacchetto separato, mi dispiace. Potresti provare a trovarlo nell'albero dei sorgenti mysql e crearlo da solo, ma questo è un sacco di problemi. Quindi hai mysql, ma non '/ usr/bin/replace'? Potresti provare a reinstallare il pacchetto mysql ('mysql-server'). –

+0

non in/usr/bin e non è possibile reinstallare! Accetterò la tua risposta supponendo che funzioni :) – EoghanM

4

opzione 1) Fuga caratteri regexp. Per esempio. sed 's/\$0\.0/0/g' sostituirà tutte le occorrenze di $ 0,0 con 0.

Opzione 2) Utilizzare perl -p -e in combinazione con quotemeta. Per esempio. perl -p -e 's/\\./,/gi' sostituirà tutte le occorrenze di . con ,.

È possibile utilizzare l'opzione 2 in uno script come questo:

SEARCH="C++" 
REPLACE="C#" 
cat $FILELIST | perl -p -e "s/\\Q$SEARCH\\E/$REPLACE/g" > $NEWLIST 
+0

Ha ottenuto un perl equivalente di sed -i? Sto usando sed come segue: find -name "* myfiles *" | xargs sed -i "s/abc/def/g" – EoghanM

+0

Sto vedendo il tuo esempio perl interpretato come un'espressione regolare! – EoghanM

+0

$ echo "a.b.c" | perl -p -e 's /./,/g' mi dà ",,,,," e non "a, b, c" – EoghanM

6

devi usare sed? Se state scrivendo uno script bash, si può fare

#!/bin/bash 
pattern='abc' 
replace='def' 
file=/path/to/file 
tmpfile="${TMPDIR:-/tmp}/$(basename "$file").$$" 
while read -r line 
do 
    echo ${line/$pattern/$replace} 
done < "$file" > "$tmpfile" && mv "$tmpfile" "$file" 

Con un guscio vecchio Bourne (come ksh88 o POSIX sh), non si può avere quel fresco ${var/pattern/replace} struttura, ma si ha ${var#pattern} e ${var%pattern}, che può essere usato per dividere la corda e poi rimontarla. Se avete bisogno di farlo, ci si trova per un codice molto di più - ma non è davvero troppo male.

Se non si è già in uno script di shell, è possibile creare facilmente i parametri pattern, replace e filename e chiamare semplicemente questo. :)

PS: la struttura $ {TMPDIR: -/tmp} utilizza $ TMPDIR se è impostata nel proprio ambiente o utilizza/tmp se la variabile non è impostata. Mi piace incollare il pid del processo corrente alla fine del nome del file nella speranza che sia leggermente più unico. Probabilmente dovresti usare mktemp o simili nel "mondo reale", ma questo è ok per un rapido esempio e il binario mktemp non è sempre disponibile.

+0

Questa è una soluzione lenta. echo viene chiamato per ogni riga del file che potrebbe biforcarsi migliaia di processi di eco se si utilizza un file di grandi dimensioni o più file. – John

+2

echo viene in genere implementato come shell incorporato, che dovrebbe forkare i processi su una shell moderna come bash. – dannysauer

+0

Puoi vedere i builtin al lavoro usando "strace -e trace = process ./shellscript". Scrivi lo script sopra e vedi quante chiamate a forcella ci sono. Usando un Bash corrente su un Ubuntu corrente, ci sono 2 fork (in realtà clone(), che è più veloce delle chiamate a fork()). Uno per la subshell in cui viene eseguito il basename e uno per il mv. Se hai riscritto questo usando "/ bin/echo", d'altra parte, allora c'è in realtà un nuovo fork per ogni riga. E potresti vederlo impiegando un * lotto * di più per l'esecuzione. :) – dannysauer

3

Se non sei contrario a Ruby o lunghe code, è possibile utilizzare questo:

alias replace='ruby -e "File.write(ARGV[0], File.read(ARGV[0]).gsub(ARGV[1], ARGV[2]))"' 

replace test3.txt abc def 

Questo carica l'intero file in memoria, esegue il sostituzioni e le salva su disco. Probabilmente non dovrebbe essere usato per file voluminosi.

1

non se ne desidera fuggire la stringa,
si può raggiungere il tuo obiettivo in 2 fasi:

fgrep la linea (ricevendo il linenumber) che si desidera sostituire,
e poi usare sed per sostituire questa linea.

ad es.

#/bin/sh 
PATTERN='foo*[)*abc' # we need it literal 
LINENUMBER="$(fgrep -n "$PATTERN" "$FILE" | cut -d':' -f1)" 

NEWSTRING='my new string' 
sed -i "${LINENUMBER}s/.*/$NEWSTRING/" "$FILE" 
Problemi correlati