2010-11-30 12 views
14

El manual de sed indica claramente que las referencias disponibles para la cadena de reemplazo en un sustituto están numeradas \ 1 a \ 9. Estoy tratando de analizar un archivo de registro que tiene 10 campos.Evite el límite de retroreferencia sed 1 a 9

Tengo la expresión regular formada pero la décima coincidencia (y cualquier cosa posterior) no es accesible.

¿Alguien tiene una forma elegante de eludir esta limitación en KSH (o en cualquier idioma que quizás yo pueda exportar a las secuencias de comandos del shell)?

+2

Usted puede utilizar casi cualquier lenguaje de programación que le permite escribir una sola línea de este. 'perl -pe 's/yourregexhere/$ 1 $ 2 $ 3 $ 4 $ 5 $ 6 $ 7 $ 8 $ 9 $ 10 /' ' –

+0

Es muy posible que pueda usar una expresión regular más simple que no necesite tantas referencias. Si muestra algunos datos de muestra y un ejemplo del resultado que desea, probablemente podamos mostrarle una forma más sencilla. –

+1

suena como un trabajo para 'awk' - el campo 10 es' $ 10' –

Respuesta

13

¿Puede usted usuario perl -pe 's/(match)(str)/$2$1/g;' en lugar de sed? La forma de eludir el límite de retroreferencia es usar algo que no sea sed.

Además, supongo que podría hacer su sustitución en dos pasos, pero no conozco su patrón así que no puedo ayudarlo con cómo.

+0

gracias esto funcionó muy bien. ahora necesito descubrir cómo generar patrones sobre la marcha y ejecutar este comando desde un script ksh, pero esa es una pregunta para otro día. –

3

Está solicitando una solución de script de shell, eso significa que no está limitado a usar solo sed, ¿correcto? La mayoría de las shells admiten matrices, ¿entonces quizás puedas analizar la línea en una variable de matriz de shell? Si es necesario, incluso podría analizar la misma línea varias veces, extrayendo diferentes bits de información en cada pasada.

¿Eso haría?

1

Considere la posibilidad de una solución que no requiera el uso de referencias regulares de retroreferencia. Por ejemplo, si tiene un delimitador de campo simple, use split, o incluso use awk para su procesamiento en lugar de perl.

3

Divida la secuencia con -e, siempre que los elementos reemplazados estén dentro del grupo con el que los dividió. Cuando hice una división de fecha para poder reorganizar la fecha y hora en una cadena de 14 dígitos, tuve que dividir la transmisión 3 veces.

echo "created: 02/05/2013 16:14:49" | sed -e 's/^\([[:alpha:]]*: \)//' -e 's/\([0-9]\{2\}\)\(\/\)\([0-9]\{2\}\)\(\/\)\([0-9]\{4\}\)\(\)/\5\1\3/' -e 's/\([0-9]\{2\}\)\(\:\)\([0-9]\{2\}\)\(\:\)\([0-9]\{2\}\)/\1\3\5/' 
0

Si tiene GNU awk, se pueden hacer cosas con mucho más en control. Para esto, necesitarías construir match(source,/regex/,array).

Ejemplo:

entrada de la muestra para la prueba:

echo "$x" 
p1=aaa,p2=bb,p3=cc,p4=dd,p5=ee,p6=ff,p7=gg,p8=hh,p9=ii,p10=jj 

sed funciona bien hasta \9:

echo $x |sed -r 's/p1=([^,]+).*p2=([^,]+).*p3=([^,]+).*p4=([^,]+).*p5=([^,]+).*p6=([^,]+).*p7=([^,]+).*p8=([^,]+).*p9=([^,]+)(.*)/\1 \2 \3 \4 \5 \6 \7 \8 \9/' 
aaa bb cc dd ee ff gg hh ii 

sed se rompió cuando se añade \10, se considera es \1 + 0.

echo $x |sed -r 's/p1=([^,]+).*p2=([^,]+).*p3=([^,]+).*p4=([^,]+).*p5=([^,]+).*p6=([^,]+).*p7=([^,]+).*p8=([^,]+).*p9=([^,]+).*p10=([^,]+)(.*)/\1 \2 \3 \4 \5 \6 \7 \8 \9 \10/' 
aaa bb cc dd ee ff gg hh ii aaa0 

awk para rescate cuando cualquier referencia de nuevo añadido se añade más de 9. A continuación se añade 10a refrence:

echo "$x" |awk '{match($0,/p1=([^,]+).*p2=([^,]+).*p3=([^,]+).*p4=([^,]+).*p5=([^,]+).*p6=([^,]+).*p7=([^,]+).*p8=([^,]+).*p9=([^,]+).*p10=([^,]+)(.*)/,a);print a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],a[10]}' 
aaa bb cc dd ee ff gg hh ii jj