sed
La API es primitiva, y esto es por diseño. Al menos, se ha mantenido primitivo por diseño, no puedo decir si fue diseñado primitivamente desde el principio. En la mayoría de los casos, la escritura de un sed
script que, cuando se ejecuta, generará otro sed
script es una cuestión simple. sed
Muy a menudo se aplica de esta manera por preprocesadores macro como m4
y / o make
.
(Lo que sigue es un caso de uso altamente hipotético: es un problema diseñado para adaptarse a una solución. Si se siente como una exageración para usted, entonces probablemente sea porque sí, pero eso no necesariamente lo hace menos válido).
Considere el siguiente archivo de entrada:
cat <<"" >./infile
camel
cat dog camel
dog cat
switch
upper
lower
Si quisiéramos escribir una sed
secuencia de comandos que anexaría el caso de palabras al final de cada palabra apropiada en el archivo de entrada anterior solo si pudiera encontrarse en una línea en el contexto apropiado , y deseamos hacerlo de la manera más eficiente posible ( como debería ser nuestro objetivo, por ejemplo, durante una operación de compilación), entonces deberíamos preferir evitar aplicar /
expresiones regulares /
tanto como sea posible.
Una cosa que podríamos hacer es editar previamente el archivo en nuestro sistema en este momento, y nunca llamar sed
en absoluto durante la compilación. Pero si alguna de esas palabras en el archivo se incluye o no en función de la configuración local y / o las opciones de tiempo de compilación, es probable que hacerlo no sea una alternativa deseable.
Otra cosa que podríamos hacer es procesar el archivo ahora contra expresiones regulares. Podemos producir, e incluir en nuestra compilación, un sed
script que puede aplicar ediciones según el número de línea, que suele ser una ruta mucho más eficiente a largo plazo.
Por ejemplo:
n=$(printf '\\\n\t')
grep -En 'camel|upper|lower' <infile |
sed " 1i${n%?}#!/usr/heirloom/bin/posix2001/sed -nf
s/[^:]*/:&$n&!n;&!b&$n&/;s/://2;\$a${n%?}q"'
s/ *cat/!/g;s/ *dog/!/g
s| *\([cul][^ ]*\).*|s/.*/\1-case/p|'
... que escribe la salida en forma de sed
script y que se parece a ...
#!/usr/heirloom/bin/posix2001/sed -nf
:1
1!n;1!b1
1s/.*/camel-case/p
:2
2!n;2!b2
2!!s/.*/camel-case/p
:5
5!n;5!b5
5s/.*/upper-case/p
:6
6!n;6!b6
6s/.*/lower-case/p
q
Cuando esa salida se guarda en un archivo de texto ejecutable en mi máquina con el nombre ./bang.sed
y se ejecuta como ./bang.sed ./infile
, la salida es:
camel-case
upper-case
lower-case
Ahora podrías preguntarme ... ¿Por qué querría hacer eso? ¿Por qué no simplemente anclar grep
los partidos? ¿Quién usa camel-case de todos modos? Y a cada pregunta que solo podía responder, no tengo idea ... porque no. ¡Antes de leer esta pregunta, nunca había notado personalmente el multi-! requisito de análisis en la especificación: creo que es una buena captura.
El multi-! Sin embargo, esto inmediatamente tenía sentido para mí: gran parte de la sed
especificación está orientada a scripts simplemente analizados y simplemente generados sed
. Probablemente encontrará los \n
delimitadores de línea electrónica necesarios para [wr:bt{]
tener mucho más sentido en ese contexto, y si tiene en cuenta esa idea, podría tener un mejor sentido de algunos otros aspectos de la especificación (como :
no aceptar direcciones y q
negarse a aceptar más de 1) .
En el ejemplo anterior, escribo una cierta forma de sed
script que solo se puede leer una vez. Si lo mira detenidamente, puede notar que a medida que sed
lee el archivo de edición, progresa de un bloque de comandos al siguiente: nunca se bifurca o completa su script de edición hasta que haya terminado completamente con su archivo de edición.
Considero que multi-! las direcciones pueden ser más útiles en ese contexto que en algunos otros, pero, sinceramente, no puedo pensar en un solo caso en el que podría haberle dado un uso muy bueno, y yo sed
mucho. También creo que es digno de mención que sed
ambos GNU / BSD no logran manejarlo como se especifica: probablemente este no sea un aspecto de la especificación que tenga mucha demanda, por lo que si una implementación lo pasa por alto, dudo mucho que sus errores @ box sufran terriblemente como resultado.
Dicho esto, no manejar esto como se especifica es un error para cualquier implementación que pretenda cumplir, por lo que creo que enviar un correo electrónico a los cuadros de desarrollo relevantes se requiere aquí, y tengo la intención de hacerlo si no lo hace.
!
actúa como un conmutador,/pattern/!!
es lo mismo/pattern/
y/pattern/!!!
es lo mismo que/pattern/!
. En FreeBSD, múltiples!
son lo mismo que uno solo.