2010-12-16 18 views
5

me gustaría sustituir un texto con un valor incremental. Teniendo en cuenta xx archivo:mínimo de la SED número

<outro>dfdfd</outro> 
<RecordID>1</RecordID> 
<outro>dfdfd</outro> 
<RecordID>1</RecordID> 
<outro>dfdfd</outro> 
<RecordID>1</RecordID> 
<outro>dfdfd</outro> 

y comando sed:

for n in seq 3;do sed -e 's/<RecordID>\d/<RecordID>'`echo $n`'/' xx; done 

el comando echo $n no consigue incrementa.

Tryed también:

n=1; sed -e 's/<RecordID>/<RecordID>'`echo $n ;let n=$n+1`'/g' xx 

pero sin éxito.

considerando sólo sed (sin awk o perl) ¿cómo puedo tener el campo RecordID incrementado como en:

<outro>dfdfd</outro> 
<RecordID>1</RecordID> 
<outro>dfdfd</outro> 
<RecordID>2</RecordID> 
<outro>dfdfd</outro> 
<RecordID>3</RecordID> 
<outro>dfdfd</outro> 
+3

Como puede ver, todo esto se vuelve muy complicado con 'sed' porque tiene que hacer el incremento fuera de él en un shell y luego llama a una instancia de sed para procesar cada línea. Si esto es sólo para fines académicos, está bien, pero realmente debes usar 'awk' para esto porque puede hacer Nativity matemática. De hecho, toda la secuencia de comandos awk es esta una línea corta: 'awk '/ RecordID/{sub (" [0-9] + ", ++ i)} 1' infile> archivo de salida' – SiegeX

+1

@SiegeX: estoy de acuerdo con su básico premisa - sed no es la herramienta correcta para el trabajo. Supongamos que los ID de los registros no se presentan en orden en el archivo; el ejemplo los muestra en orden, pero no está claro si los números son necesariamente monótonamente crecientes o incluso en secuencia ... ¿con qué facilidad 'awk' maneja la captura y luego modificación de parte de la línea? Mi sospecha es "no muy fácil"; es en ese momento cuando me dirijo a Perl (aunque aceptaría Python como una alternativa completamente adecuada para Perl; por casualidad, sé que Perl es mejor que Python). ¿Alguna opinión? –

+1

@Jonathan Cuando desee hacer algo desordenado con awk, generalmente requiere el uso de matrices asociativas. Y aunque puede ser un poco incómodo (sin juego de palabras), ciertamente no lo pondría en la categoría "no muy fácil". No estoy muy seguro de cómo quiere que cambie la entrada de O/P para mostrar esto, pero he aquí un ejemplo que lancé hace poco que hizo un uso exhaustivo de las matrices asociativas de awk http://stackoverflow.com/questions/4443583/bash-script-that-analyze-report-files/4445671 # 4445671 – SiegeX

Respuesta

5
while read line; do n=$((++n)) && echo $line|sed -e 's/[0-9]/'$(($n))'/' ; done < patt 
+1

El segundo '$ (())' no es necesario, solo usa '$ n'. –

+0

mientras lee la línea; do if ["$ (echo $ line | grep Re)"]; entonces n = $ ((++ n)) && línea de $ echo | sed -e 's/[0-9] /' $ n '/' demás : fi done < – Someguy

+0

Patt Los soportes, cotizaciones y la sustitución de comandos no son necesarios en la versión de tu comentario: 'if echo" $ line "| grep -qs Re' –

2

En primer lugar, sed no entiende \d. Use [0-9] o [[:digit:]] en su lugar.

En segundo lugar, for n in seq 3 establecerá n en "seq" y "3". Use for n in $(seq 3) o (en Bash) use for n in {1..3}.

En tercer lugar, es necesario guardar el resultado de su sustitución. Si su versión de sed apoya -i (en el lugar), puede usar eso, o puede que tenga que utilizar sed ... xx > xx.tmp && mv xx.tmp xx.

En cuarto lugar, es necesario seleccionar qué línea para hacer el cambio a.

poner toda esa juntos y esto funciona, pero podría ser bastante lento:

for n in $(seq 3); do sed -e $(($n*2))'s/<RecordID>[[:digit:]]/<RecordID>'$n'/' xx > xx.tmp && mv xx.tmp xx; done 
+0

La forma general de la respuesta de Charles es probablemente más eficiente. –

+0

El primer pase mapea todos los valores de ID 0..9 a 2; el segundo pase mapea todos los 2 a 4; el tercer pase mapea todos los 4 a 6 ... ¿no? –

+0

@Jonathan: No, porque '' $ (($ n * 2)) 'selecciona en qué línea operar. –

4

A pesar de la declaración en la pregunta que Perl y Awk no se pueden utilizar, las respuestas dadas hasta ahora demuestran que sed no es el herramienta correcta para esta tarea. Las dos respuestas que veo solo funcionan con un conjunto extremadamente limitado de datos y solo funcionan de forma sana en conjuntos de datos extremadamente pequeños.

Usando sed, no es un método sensato disponibles para hacer frente a miles de registros. Puede hackear soluciones juntas, si tiene cuidado, que se ocupen de tres ID de registro (sugerencia: es posible que necesite mapear 3 a 4 antes de mapear 2 a 3, para que los 3 asignados no se reasignen a 4).

Utilizando Perl o Python, es factible.

perl -e 's{<RecordID>(\d+)</RecordID>}{$n=$n+1; "<RecordID>$n</RecordID>"}e' 

Se trata en muchos casos de "utilizar la herramienta adecuada para el trabajo". sed es una gran herramienta para los trabajos para los que está diseñado (y muchos para los que no fue diseñado). Sin embargo, esto es demasiado estresante.

+4

+1 para la herramienta correcta. A veces, sin embargo, te enfrentas a un clavo que necesita golpes y solo tiene un destornillador. ¿Qué harás despues? (Me gustaría beber el destornillador y decir "atornillar la uña". Entonces los golpes serían todo en mi cabeza.) –

+0

¿cómo se usa esto con un archivo? – olivervbk

+0

@OliverKuster: especifica el nombre del archivo después de la parte '-e '...'' de la secuencia de comandos. Eso escribirá la salida a salida estándar. Si desea que la salida sobrescriba el archivo original, agregue una opción como '-i.bak' antes de' -e' (pero primero pruebe los cambios). –

0

La verdadera manera de hacer esto con sed es, por supuesto, para obviar la necesidad de bucles en el caparazón. Utilice algo así como la coincidencia de direcciones de Denis para reducir el alcance, luego use las expresiones del script in sed's info pages. Aumenta léxicamente los números, sin aritmética involucrada. El único truco que hace es cuidar el acarreo.

Cuestiones relacionadas