2011-01-30 16 views
10

tengo que aplicar el comando Unix sed en una cadena (puede contener #,?, /,, &, @ y todos los demás!? !? carácteres), que puede contener todo tipo de caracteres (&, |,, /, ...)sed rara-delimitador (que no sean & |?/...)

¿es un delimitador compleja (con dos caracteres de) los cuales pueden permisos para outpass el error:

?
sed: -e expression #1, char 22: unknown option to `s' 

Gracias de antemano

+0

Por lo menos, muéstrenos la cadena que está dando a sed que causa el error. –

+0

Las cadenas pasadas en sed pueden contener #,!, /,?, &, @ Y todos los demás caracteres – Unitech

Respuesta

1

No existe tal opción para los delimitadores de expresión de múltiples caracteres en sed, pero dudo que lo necesite. El carácter delimitador no debería aparecer en el patrón , pero si aparece en la cadena que se está procesando, no es un problema. Y a menos que esté haciendo algo extremadamente extraño, siempre habrá algún personaje que no aparezca en su patrón de búsqueda que pueda servir como delimitador.

+0

Estoy haciendo algo extremadamente raro, sí. Estoy probando todo tipo de personajes. – Unitech

+0

@tknew: solo Perl pero no sed ofrece coincidencias que son independientes de un delimitador. Como Perl es un superconjunto apropiado de sed, esto puede ser suficiente. – tchrist

+0

Me encontré con este problema el otro día, y no creo que lo que estoy haciendo sea extremadamente extraño: estaba intentando eliminar una línea que contiene una cadena arbitraria '$ STR', p. Ej. 'sed -i -e '/'" $ STR "'/ d' $ FILE'. ¿O hay una mejor expresión para lo anterior? –

11

Los caracteres en el archivo de entrada no son relevantes - sed los analiza bien. Sin embargo, puede haber un problema si tiene la mayoría de los caracteres comunes en su patrón - o si su patrón no se conoce de antemano.

Al menos en GNU sed, puede utilizar un carácter no imprimible que es altamente improbable que exista en su patrón como un delimitador. Por ejemplo, si su cáscara es Bash:

$ echo '|||' | sed s$'\001''|'$'\001''/'$'\001''g' 

En este ejemplo, Bash replaces$'\001' con el carácter que tiene el valor octal 001 - en ASCII es el carácter SOH (comienzo de la partida).

Dado que tales caracteres son de control/no imprimibles, es dudoso que existan en el patrón. A menos que, es decir, esté haciendo algo extraño como modificar archivos binarios, o archivos Unicode sin la configuración de configuración regional adecuada.

+0

Caracteres no imprimibles pueden aparecer en el patrón de búsqueda, pero gracias por la sugerencia – Unitech

+0

"Muy improbable" no es lo mismo que imposible.No puede hacer coincidencias en sed sin * algún * delimitador, lo que siempre causará un problema si ese delimitador está en el patrón. En Perl, sin embargo, puedes. – tchrist

+0

Esto funciona muy bien. @Tknew - ¿Qué tipo de texto está tratando? Esta solución es casi la mayoría de los conjuntos de datos. ¿Estás lidiando con texto o binario? El byte nulo es seguro para procesar nombres de archivos, pero para datos de texto reales no existe un carácter seguro que pueda garantizar más que los no imprimibles. Tengo una solución a este problema en un script que escribí, que implica buscar y reemplazar el texto hasta encontrar un único centinela. Eso es todo lo que sé que se puede hacer para este problema en este momento, si quieres puedes verificar la lógica de mi script: http://goo.gl/0bypeu –

1

Necesita la facilidad de delimitador anidado que Perl ofrece. Eso permite usar cosas como emparejar, sustituir y transliterar sin preocuparse de que el delimitador esté incluido en sus contenidos. Como perl es un superconjunto de sed, deberías poder usarlo para lo que sea que utilices sed.

Considera:

$ perl -nle 'print if /something/' inputs 

Ahora si su something contiene una barra, tiene un problema. La forma de solucionar esto es cambiar el delimitador, preferiblemente a uno de horquillado. Así, por ejemplo, puede tener lo que quiera en el $ LO variable de shell (siempre los backets están en equilibrio), que consigue interpolada por la cáscara antes de Perl es aún llamado aquí:

$ perl -nle "print if m($WHATEVER)" /usr/share/dict/words 

que funciona incluso si tiene paréntesis anidados correctamente en $ WHATEVER. Los cuatro pares de horquillado que anidan correctamente así en Perl son < >, (), [ ] y { }. Permiten contenidos arbitrarios que incluyen el delimitador si ese delimitador está equilibrado.

Si es no balanceado, entonces no use un delimitador en absoluto.Si el patrón es una variable en Perl, que no es necesario utilizar el operador encuentro, siempre se utiliza el operador =~, por lo que:

$whatever = "some arbitrary string (/ # [ etc"; 
if ($line =~ $whatever) { ... } 
1

Con la ayuda de Jim Lewis, finalmente me hice una prueba antes de usar SED :

if [ `echo $1 | grep '|'` ]; then 
    grep ".*$1.*:" $DB_FILE | sed "[email protected]^.*$1*.*\(:\)@@ " 
else 
    grep ".*$1.*:" $DB_FILE | sed "s|^.*$1*.*\(:\)|| " 
fi 

Gracias por la ayuda

+0

Sí, iba a publicar una solución que haga la lógica de de este tipo: básicamente, podría hacer un ciclo sobre todos los caracteres que determinarán semi-exhaustivamente el primer carácter que no está presente en su cadena de búsqueda propuesta, entonces el único caso que fallaría sería si su cadena de búsqueda contenía * todos * caracteres posibles, que es una situación bastante absurda –

0

Wow. No sabía que pudieras usar cualquier carácter como delimitador. Al menos la mitad de las veces uso sed y BREs en rutas, fragmentos de código, caracteres basura, cosas por el estilo. Terminé con un montón de escapes horriblemente ilegibles que ni siquiera estoy seguro de que no vaya a morir en una combinación que no pensé. Pero si se puede excluir sólo algunas clase de caracteres (o sólo un carácter aún)

echo '#01Y $#1+!' | sed -e 'sa$#1+ashita' -e 'su#01YuHolyug'

> > > Holy shit! Eso es lo que mucho más fácil.

1

Otra forma de hacerlo es utilizar la sustitución de parámetros de la carcasa.

${parameter/pattern/replace} # substitute replace for pattern once 

o

${parameter//pattern/replace} # substitute replace for pattern everywhere 

Aquí es un ejemplo bastante complejo que es difícil con SED:

$ parameter="Common sed delimiters: [sed-del]" 
$ pattern="\[sed-del\]" 
$ replace="[/_%:\\@]" 
$ echo "${parameter//$pattern/replace}" 

resultado es:

Common sed delimiters: [/_%:\@] 

Sin embargo:Esto solo funciona con los parámetros de bash y no con los archivos donde sobresale sed.

+0

Voto a favor de la respuesta irrelevante tag-on-rep realmente tardía que ignora la pregunta que requiere explícitamente el uso de la entrada de sed y archivo. – Grod

+0

Bueno Gordon, bien por ti. Sin embargo llegué a esta página cuando tuve un problema similar al presentado aquí. Esta página no me dio ninguna solución a mi problema, pero sí la sustitución de parámetros. Como creo que otros podrían llegar a esta página sin saber que la sustitución de los parámetros podría ser la respuesta a su problema, considero que mi respuesta es una contribución. En mi humilde opinión, stackoverflow no está aquí solo para responder a quienes hacen la pregunta, sino también a otros que buscan una solución a un problema específico. Mi respuesta es solo eso. – javabeangrinder

+0

No cambia que esta no es una respuesta a la pregunta aquí. FYI, puede crear su propia pregunta y responderla usted mismo con el fin de compartir una solución que encontró con algún problema cuando las preguntas existentes no se aplican. – Grod

0

Escapar el delimitador en línea para el análisis de BASH es engorroso y difícil de leer (aunque el delimitador necesita escaparse para beneficio de sed cuando se usa por primera vez, por expresión).

para reunir thkala 's respuesta y user4401178' s comentario:

DELIM=$(echo -en "\001"); 
sed -n "\\${DELIM}${STARTING_SEARCH_TERM}${DELIM},\\${DELIM}${ENDING_SEARCH_TERM}${DELIM}p" "${FILE}" 

Este ejemplo devuelve todos los resultados a partir de ${STARTING_SEARCH_TERM} hasta ${ENDING_SEARCH_TERM} que no coinciden con la SOH (inicio de la partida) carácter con el código ASCII 001.

Cuestiones relacionadas