2010-02-13 33 views
5

Estoy usando sed -e "s/\*DIVIDER\*/$DIVIDER/g" para reemplazar *DIVIDER* con una cadena especificada por el usuario, que se almacena en $DIVIDER. El problema es que quiero que puedan especificar caracteres de escape como su divisor, como \ n o \ t. Cuando pruebo esto, acabo con la letra n o t, etc.Usar sed para reemplazar una cadena con el contenido de una variable, incluso si es un carácter de escape

¿Alguien tiene alguna idea sobre cómo hacer esto? ¡Será muy apreciado!

EDITAR: Aquí está la carne del guión, me falta algo.

curl --silent "$URL" > tweets.txt 

if [[ `cat tweets.txt` == *\<error\>* ]]; then 
    grep -E '(error>)' tweets.txt | \ 
    sed -e 's/<error>//' -e 's/<\/error>//' | 
    sed -e 's/<[^>]*>//g' | 

head $headarg | sed G | fmt 

else 
    echo $REPLACE | awk '{gsub(".", "\\\\&");print}' 
    grep -E '(description>)' tweets.txt | \ 
    sed -n '2,$p' | \ 
    sed -e 's/<description>//' -e 's/<\/description>//' | 
    sed -e 's/<[^>]*>//g' | 
    sed -e 's/\&amp\;/\&/g' | 
    sed -e 's/\&lt\;/\</g' | 
    sed -e 's/\&gt\;/\>/g' | 
    sed -e 's/\&quot\;/\"/g' | 
    sed -e 's/\&....\;/\?/g' | 
    sed -e 's/\&.....\;/\?/g' | 
    sed -e 's/^ *//g' | 
    sed -e :a -e '$!N;s/\n/\*DIVIDER\*/;ta' | # Replace newlines with *divider*. 
    sed -e "s/\*DIVIDER\*/${DIVIDER//\\/\\\\}/g" |   # Replace *DIVIDER* with the actual divider. 

    head $headarg | sed G 
fi 

La larga lista de líneas sed están reemplazando los caracteres de una fuente XML, y los dos últimos son los que se supone que deben sustituir a los saltos de línea con el carácter especificado. Sé que parece redundante reemplazar una línea nueva con otra línea nueva, pero fue la forma más fácil que pude encontrar para dejarles elegir su propio divisor. El reemplazo del divisor funciona muy bien con los caracteres normales.

+4

su guión está mal escrita. una gran cantidad de pasos de sed innecesarios. Muestre el archivo de entrada que está procesando y muestre el resultado deseado. – ghostdog74

Respuesta

7

Puede usar bash para escapar de la barra invertida como esto:

sed -e "s/\*DIVIDER\*/${DIVIDER//\\/\\\\}/g" 

El la sintaxis es ${name/pattern/string}. Si el patrón comienza con /, cada ocurrencia de pattern en name se reemplaza por string. De lo contrario, solo se reemplaza la primera ocurrencia.

+0

Con esto acabo de terminar con una doble barra invertida y una "n" insertada en la secuencia. Tal vez es la forma en que estoy canalizando las cosas. Editaré la publicación original para incluir más de la secuencia de comandos. – vilhalmer

+1

la solución de tangens trata con las barras diagonales inversas, pero no con \ n o the \ t. El problema es que sed no reconoce \ n o \ t. Puede ponerlos en DIVIDER explícitamente, o canalizar la salida a través de otro filtro para reemplazar \ n con una nueva línea. por ejemplo: sed '/ \\ n/\ /g' –

+0

Esa es una buena idea, podría volver a conectarla a través de tr en el camino de salida. ¡Gracias! – vilhalmer

0

Solo necesita escapar del char de escape.

\ n coincidirá \ n

\ coincidirá \

\\ coincidirá \

+0

Lo intenté \\\ n, y terminó como \ n, pero lo imprimió literalmente. ¿Cómo hago para que Sed lo interprete como un escape en lugar de una cadena normal? – vilhalmer

1

Tal vez:

case "$DIVIDER" in 
(*\\*) DIVIDER=$(echo "$DIVIDER" | sed 's/\\/\\\\/g');; 
esac 

He jugado con este script:

for DIVIDER in 'xx\n' 'xxx\\ddd' "xxx" 
do 
    echo "In: <<$DIVIDER>>" 
    case "$DIVIDER" in  (*\\*) DIVIDER=$(echo "$DIVIDER" | sed 's/\\/\\\\/g');; 
    esac 
    echo "Out: <<$DIVIDER>>" 
done 

Ejecutar con 'ksh' o 'fiesta' (pero no 'sh') en MacOS X:

In: <<xx\n>> 
Out: <<xx\\n>> 
In: <<xxx\\ddd>> 
Out: <<xxx\\\\ddd>> 
In: <<xxx>> 
Out: <<xxx>> 
1

Parece ser una simple sustitución:

$ d='\n' 
$ echo "a*DIVIDER*b" | sed "s/\*DIVIDER\*/$d/" 
a 
b 

Quizás no entiendo lo que estás tratando de lograr.

Entonces tal vez este paso podría tomar el lugar de los dos últimos de los suyos:

sed -n ":a;$ {s/\n/$DIVIDER/g;p;b};N;ba" 

Observa el espacio después del signo de dólar. Impide que el shell interprete "$ {s ..." como un nombre de variable.

Y como ghostdog74 sugerido, tiene demasiadas llamadas al sed. Es posible que pueda cambiar muchos de los caracteres de tubería a barras invertidas (continuación de línea) y eliminar "sed" de todos menos del primero (deje el "-e" en todas partes).(No probado)

+0

¡Gracias por la información sobre las llamadas innecesarias a los seds! Escribí esto hace bastante tiempo y no sabía mucho sobre scripts sed o shell en general. – vilhalmer

+0

He intentado combinar las llamadas con continuación y todo en una línea, pero algunos de los reemplazos dejan de funcionar. Ya no elimina las etiquetas ni el espacio adicional. ¿Hay algún orden mágico en el que necesiten estar? – vilhalmer

+0

¿Lo dejaste en su lugar? 'sed -n '2, $ p' | sed ... 'Estás seleccionando las líneas para actuar al hacer esto. Si saca la tubería aquí, podría no funcionar. Sin ver los datos y su script revisado, no puedo decirlo con certeza. Debe tener en cuenta que de esta manera se encuentra la locura (usando expresiones regulares en HTML): http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 –

0

Usando FreeBSD sed (por ejemplo en Mac OS X) que tiene que procesar previamente el $ de entrada del usuario DIVISOR:

d='\n' 
d='\t' 
NL=$'\\\n' 
TAB=$'\\\t' 
d="${d/\\n/${NL}}" 
d="${d/\\t/${TAB}}" 
echo "a*DIVIDER*b" | sed -E -e "s/\*DIVIDER\*/${d}/" 
Cuestiones relacionadas