2015-01-05 7 views
45

In realtà conosco la risposta a questa domanda, tuttavia più di una volta ho visto alcuni dei miei colleghi bloccati su questo problema, quindi ho pensato che sarebbe valsa la pena di documentarlo COSÌ. Se la domanda esiste già, la eliminerò volentieri.Come passare una variabile contenente barre a sed

Quindi qui si va ...

Come si fa a passare una variabile contenente barre come un modello per sed.

Per esempio, se ho la seguente variabile:

var="/Users/Documents/name/file" 

voglio passarlo a sed come così:

sed "s/$var/replace/g" $file 

Tuttavia ottengo errori. Come posso eludere il problema?

risposta

79

Utilizzare un delimitatore regex alternativo come sed consente di utilizzare qualsiasi delimitatore (compresi i caratteri di controllo):

sed "s~$var~replace~g" $file 
+1

Non funziona. Provo sed -i "s ~ blah ~ $ var ~ g file" e ottengo: "sed -e espressione # 1, char 70: comando 's' non terminato. Ho confermato che il colpevole è un taglio di $ var. Varianti di questa soluzione a questo sono dappertutto e nessuno di loro funziona. È stato recentemente aggiornato? Sono su v4.2.2 su Ubuntu 14.04.4 LTS. –

+0

Dipende dal valore di '$ var' – anubhava

+1

Non funziona con ~ come osservato da @PaulEricson, ma funziona ancora con | –

23

Un puro bash risposta: utilizzare parameter expansion al backslash-sfuggire eventuali tagli nella variabile:

var="/Users/Documents/name/file" 
sed "s/${var//\//\\/}/replace/g" $file 
+0

Questo è un buon modo, perché non si sa sempre quali caratteri contiene la variabile. Quindi puoi sempre scappare dal delimitatore di sed se c'è un dubbio. Ad esempio: sed "s: $ {var //:/\\:}: sostituisci: g" $ file –

+0

Beautiful. Ho reso alcuni miei script di ridenominazione molto più puliti. – DevNull

+0

Questo mi ha aiutato molto, grazie :) – gabtzi

21

un altro modo di farlo, anche se più brutto di risposta di anubhava, è fuggendo tutti i backslash in var utilizzando un altro sed comando:

var=$(echo "$var" | sed 's/\//\\\//g') 

allora, questo funzionerà:

sed "s/$var/replace/g" $file 
5

Utilizzando / in sed come delimitatore in conflitto con le barre nella variabile quando sostituito e come risultato si otterrà un errore. Un modo per aggirare questo è usare un altro delimitatore che è unico da qualsiasi carattere che si trova in quella variabile.

var="/Users/Documents/name/file" 

è possibile utilizzare il carattere cancelletto che si adatta l'occasione (o qualsiasi altro carattere che non è un / per la facilità d'uso)

sed "s#$var#replace#g" 

o

sed 's#$'$var'#replace#g' 

questo è adatto quando la variabile non contiene spazi

o

sed 's#$"'$var'"#replace#g' 

E 'più saggio utilizzare il sopra dal momento che siamo interessati a sostituire ciò che è in quella variabile solo rispetto a raddoppiare citando l'intero comando che può causare la shell per interpretare gli qualsiasi carattere che potrebbe essere considerato un guscio speciale personaggio alla shell.

+0

Non funziona. Provo sed -i "s ~ blah ~ $ var ~ g file" e ottengo: "sed -e espressione # 1, char 70: comando 's' non terminato. Ho confermato che il colpevole è un taglio di $ var. Varianti di questa soluzione a questo sono dappertutto e nessuno di loro funziona. È stato recentemente aggiornato? Sono su v4.2.2 su Ubuntu 14.04.4 LTS. –

1

Il delimitatore alternativo funziona solo quando è necessario cercare e sostituire. In casi come i casi in cui è necessario eliminare righe dal file in base alla parola contenente/(ad esempio /dev/sda1), non funzionerà. Prua, testa.g:

var1=/dev/sda1 
sed -i ":$var1:d" $file 

vorrei andare con la soluzione proposta da @Bolboa