2011-08-05 7 views
7

archivo tengo que modificar contiene lo siguiente:¿Es posible la sustitución de Sed con aritmética?

block: 16, size: 16, start: 8, length: 4 

Me gustaría que el archivo para que los valores de bloque, tamaño se divide por 2, mientras que los valores para el inicio , longitud se multiplicará por 2.

Como tengo que hacer tales modificaciones para un montón de archivos, estoy considerando usar Sed para hacer el trabajo de sustitución por mí. Pero no estoy seguro de que los cálculos estén permitidos en el proceso de emparejamiento y sustitución.

Respuesta

8

Siempre trato de resolver cada problema etiquetado con usando sed. Pero aquí sería tan fácil lograr lo que estás tratando de hacer con awk. (Y el uso de sed en este caso es demasiado difícil.) Así pues, aquí está mi solución utilizando awk:

$ echo "block: 16, size: 16, start: 8, length: 4" | awk '{ 
    printf "%s %d, %s %d, %s %d, %s %d\n", $1, $2/2, $3, $4/2, $5, $6*2, $7, $8*2 
}' 
block: 8, size: 8, start: 16, length: 8 
+1

Esto no funciona como se espera cuando el orden de las entradas es diferente, e. gramo. '" bloque: 16, inicio: 8, tamaño: 8, largo: 4 "' –

0

no creo que sea posible. Ver p. http://www.delorie.com/gnu/docs/sed/sed_15.html.

Sin embargo si sólo tiene un pequeño conjunto de valores posibles para el bloque, tamaño, iniciar y longitud, que podría ser más rápida para codificar las sustituciones necesarias. La siguiente opción más fácil es usar awk, pero eso no puede modificar los archivos in situ.

5

Perl es útil aquí:

perl -pe ' 
    s{(\D+)(\d+)(\D+)(\d+)(\D+)(\d+)(\D+)(\d+)} 
    {$1 . $2/2 . $3 . $4/2 . $5 . $6*2 . $7 . $8*2}e 
' file 

Si desea editar sus archivos en -place, perl tiene una opción -i como sed.

+1

Quiere decir que * sed * tiene la opción '-i' como * perl *, y no al revés. No encontrará una opción '-i' en la lista de opciones requerida en la especificación POSIX para * sed *, por cierto, sino ocasionalmente y extraoficialmente en ciertos puertos de proveedores. LEER: 'sed -i' ** no es universalmente compatible **, aunque' perl -i' es. – tchrist

5

(La herramienta adecuada para hacer esto es awk, pero para la diversión de un ejercicio de sed ...)

es posible en sed. Después de todo, una multiplicación por 2 es un conjunto de sustitución del último dígito de acuerdo con algunas reglas simples:

  • 0 -> 0
  • 1 -> 2
  • 2 -> 4
  • 3 -> 6
  • ...
  • 8 -> 16
  • 9 -> 18

Para cuidar el dígito de acarreo, cada regla debe escribirse dos veces.

Esta secuencia de comandos sed, que se puede ejecutar con sed -f script, hacer la multiplicación por 2 de todos los números en las líneas de entrada:

s/$/\n\n/ 
:loop 
s/0\n1\n/\n\n1/;t loop 
s/0\n\n/\n\n0/;t loop 
s/1\n1\n/\n\n3/;t loop 
s/1\n\n/\n\n2/;t loop 
s/2\n1\n/\n\n5/;t loop 
s/2\n\n/\n\n4/;t loop 
s/3\n1\n/\n\n7/;t loop 
s/3\n\n/\n\n6/;t loop 
s/4\n1\n/\n\n9/;t loop 
s/4\n\n/\n\n8/;t loop 
s/5\n1\n/\n1\n1/;t loop 
s/5\n\n/\n1\n0/;t loop 
s/6\n1\n/\n1\n3/;t loop 
s/6\n\n/\n1\n2/;t loop 
s/7\n1\n/\n1\n5/;t loop 
s/7\n\n/\n1\n4/;t loop 
s/8\n1\n/\n1\n7/;t loop 
s/8\n\n/\n1\n6/;t loop 
s/9\n1\n/\n1\n9/;t loop 
s/9\n\n/\n1\n8/;t loop 
s/\n1\n/\n\n1/;t loop 
s/\(.\)\n\n/\n\n\1/;t loop 
s/^\n\n// 

La división de un número par por 2, es la misma lógica, pero a partir de de izquierda a derecha en vez de derecha a izquierda:

s/^/\n\n/ 
:loop 
s/\n1\n0/5\n\n/;t loop 
s/\n\n0/0\n\n/;t loop 
s/\n1\n1/5\n1\n/;t loop 
s/\n\n1/\n1\n/;t loop 
s/\n1\n2/6\n\n/;t loop 
s/\n\n2/1\n\n/;t loop 
s/\n1\n3/6\n1\n/;t loop 
s/\n\n3/2\n1\n/;t loop 
s/\n1\n4/7\n\n/;t loop 
s/\n\n4/2\n\n/;t loop 
s/\n1\n5/7\n1\n/;t loop 
s/\n\n5/2\n1\n/;t loop 
s/\n1\n6/8\n\n/;t loop 
s/\n\n6/3\n\n/;t loop 
s/\n1\n7/8\n\n/;t loop 
s/\n\n7/3\n1\n/;t loop 
s/\n1\n8/9\n\n/;t loop 
s/\n\n8/4\n\n/;t loop 
s/\n1\n9/9\n1\n/;t loop 
s/\n\n9/4\n1\n/;t loop 
s/\n1\n/5\n\n/;t loop 
s/\n\n\(.\)/\1\n\n/;t loop 
s/\n\n$// 

Combinando esos, este script hace el trabajo:

h 
s/, start.*// 
s/^/\n\n/ 
t loopa 
:loopa 
s/\n1\n0/5\n\n/;t loopa 
s/\n\n0/0\n\n/;t loopa 
s/\n1\n1/5\n1\n/;t loopa 
s/\n\n1/\n1\n/;t loopa 
s/\n1\n2/6\n\n/;t loopa 
s/\n\n2/1\n\n/;t loopa 
s/\n1\n3/6\n1\n/;t loopa 
s/\n\n3/2\n1\n/;t loopa 
s/\n1\n4/7\n\n/;t loopa 
s/\n\n4/2\n\n/;t loopa 
s/\n1\n5/7\n1\n/;t loopa 
s/\n\n5/2\n1\n/;t loopa 
s/\n1\n6/8\n\n/;t loopa 
s/\n\n6/3\n\n/;t loopa 
s/\n1\n7/8\n\n/;t loopa 
s/\n\n7/3\n1\n/;t loopa 
s/\n1\n8/9\n\n/;t loopa 
s/\n\n8/4\n\n/;t loopa 
s/\n1\n9/9\n1\n/;t loopa 
s/\n\n9/4\n1\n/;t loopa 
s/\n1\n/5\n\n/;t loopa 
s/\n\n\(.\)/\1\n\n/;t loopa 
s/\n\n$// 
H 
g 
s/.*, start/, start/ 
s/\n.*// 
s/$/\n\n/ 
t loopb 
:loopb 
s/0\n1\n/\n\n1/;t loopb 
s/0\n\n/\n\n0/;t loopb 
s/1\n1\n/\n\n3/;t loopb 
s/1\n\n/\n\n2/;t loopb 
s/2\n1\n/\n\n5/;t loopb 
s/2\n\n/\n\n4/;t loopb 
s/3\n1\n/\n\n7/;t loopb 
s/3\n\n/\n\n6/;t loopb 
s/4\n1\n/\n\n9/;t loopb 
s/4\n\n/\n\n8/;t loopb 
s/5\n1\n/\n1\n1/;t loopb 
s/5\n\n/\n1\n0/;t loopb 
s/6\n1\n/\n1\n3/;t loopb 
s/6\n\n/\n1\n2/;t loopb 
s/7\n1\n/\n1\n5/;t loopb 
s/7\n\n/\n1\n4/;t loopb 
s/8\n1\n/\n1\n7/;t loopb 
s/8\n\n/\n1\n6/;t loopb 
s/9\n1\n/\n1\n9/;t loopb 
s/9\n\n/\n1\n8/;t loopb 
s/\n1\n/\n\n1/;t loopb 
s/\(.\)\n\n/\n\n\1/;t loopb 
s/^\n\n// 
H 
g 
s/[^\n]*\n// 
s/\n// 

(Mucho más fácil en awk pensado.)

Nota: Una vez vi una implementación de la máquina Turing es sed, así que trato de recordar que todo lo que se puede hacer con un lenguaje de programación se puede hacer en sed. Eso, por supuesto, no significa que sed sea la buena herramienta en todas las situaciones.

+0

No he tratado de entender esto, pero en base a su comentario, parece que esto fallará con cualquier cosa que no sean números de un dígito. No puedes reemplazar solo el último número de forma aislada. –

+0

Sé que no puedo reemplazar solo el último número de forma aislada. Es por eso que tengo 2 '\ n'. Para la multiplicación, a la derecha está la solución, y en el medio el dígito de acarreo. – jfg956

Cuestiones relacionadas