con respecto a sed portátil -e ... db o! ¿si?


12

En esta edición, Stéphane Chazelas POSIXifica (nuevamente) mi sedformato insertando un -esalto de expresión y otra -edeclaración de expresión. Ahora, podría preguntarle por qué en los comentarios, supongo, pero ya es la revisión número 18 en esa respuesta y casi todas las anteriores ya fueron gracias a regalos similares (si puede ver comentarios eliminados, sabrá qué me refiero) . Además, creo que estoy lo suficientemente cerca como para entender por qué expresar esto de una manera que podría ser más útil en general. Así que aquí está esperando ...

En general, prefiero mantener mi sed -expressions total en uno si pudiera, pero también tengo una mayor preferencia por cumplir con la especificación lo más cerca posible, especialmente cuando la diferencia no es más que ay <space>an -e. Pero no puedo hacer esto si no entiendo por qué debería hacerlo. Aquí hay un breve resumen del estado actual de mi comprensión:

  • la ' -e 'ruptura puede representar portátilmente una sedsecuencia de comandos \newline break en una seddeclaración de línea de comando ... Estoy ciertamente confuso sobre por qué

  • la llave de cierre en una sed {función }debe estar precedida por un \nsalto de línea de conexión como se indica aquí:

    • El <right-brace>debe ir precedido de a <newline>y puede ir precedido o seguido de <blank>caracteres.
  • una \nruptura ewline se requiere de manera similar después de cualquier uso de ... a, b, c, i, r, t, w, o :.

Pero no entiendo claramente cómo la definición de la {función }se relaciona con el !operador no. La única mención que encuentro del operador de negación en los estados de especificación:

  • Una función puede estar precedida por uno o más !caracteres, en cuyo caso la función se aplicará si las direcciones no seleccionan el espacio del patrón.

¿Significa esto que el uso de a !implica {llaves }? ¿Qué pasa con los $!comandos? ¿Deberían también estar separados por ' -e 'saltos? ¿Fue esto lo que se abordó cuando Stéphane más recientemente POSIXificó mi respuesta?

Creo que es el !operador de negación o la bdeclaración de rancho que aborda en su edición, o posiblemente ambas cosas a la vez, pero no lo sé y me gustaría. Si es solamente la bdeclaración de hacienda, entonces creo un dharía en su lugar y eliminar la necesidad de la ' -e 'ruptura, pero yo prefiero estar seguro antes de arriesgar un tres veces POSIXified respuesta. ¿Puede usted ayudar?

Lo arriesgué después de todo , pero no con mucha certeza ...


Con b;n;:b, se está bifurcando a la etiqueta llamada ";n;:b"en seds históricos y POSIX (y GNU sed no está en ese sentido).
Stéphane Chazelas

@ StéphaneChazelas - Entiendo el :papel - condujiste a casa hace meses. Pero no entiendo completamente por qué el segundo sedcomando se POSIXificó de manera similar .
mikeserv

1
En cualquier caso, la especificación POSIX para no sedestá muy clara para mí. He solicitado aclaraciones varias veces en el pasado, pero no creo que se haya actualizado como resultado. Una buena prueba es probar con el hecheloom toolchest (uno de Solaris, derivado del original y en el que se basa en gran medida la especificación POSIX).
Stéphane Chazelas

1
@syntaxerror: no creo que ese sea el caso. si lee la especificación, encontrará que las s///sustituciones están especificadas para aceptar el encadenamiento con a ; . se vuelve borroso alrededor de los comandos que deben delimitarse con una nueva línea y cómo -epuede intervenir en ese caso, al menos para mí. Sin embargo, todavía tengo que tropezar con un sedque no los interpreta de manera bastante intercambiable.
mikeserv

1
@syntaxerror: me gusta, pero debes saber que no necesitas el ;antes de una nueva línea, una nueva línea está bien. Honestamente, podría prescindir del -ey todo por completo y simplemente escribir un archivo como #!/bin/sedcon cada comando en una nueva línea, o aquellos que no requieren tales delimitadores en su lugar delimitados ;. Los que lo requieren nuevas líneas son generalmente los que tienen de entrada arbitrarias - :nombres de las etiquetas y los comandos que se refieren a ellos como bo to cerrar }curlies para las funciones, o rEAD y writo que toman argumentos de nombre de archivo. Todos ellos deben ser seguidos de forma portátil \n.
mikeserv

Respuestas:


4

Así que ya es hora de que esta pregunta tenga una respuesta, y, aunque eventualmente resolví intuitivamente cómo hacerlo correctamente en casi todos los casos hace algún tiempo, solo recientemente logré concretar bastante esa comprensión con el texto en el estándar . En realidad, se afirma allí de manera bastante simple: supongo que lo pasé por alto estúpidamente muchas veces.

Las partes relevantes del texto se encuentran todas bajo el encabezado ...

  • Edición de comandos ensed :

    • El texto del argumento consistirá en una o más líneas. Cada línea \nelectrónica incrustada en el texto irá precedida de una \barra diagonal inversa. Se eliminarán otras barras invertidas en el texto y el siguiente carácter se tratará literalmente.

    • Los verbos de comando ry w, y el windicador al scomando, toman un parámetro opcional rfile (o wfile ), separado de la letra o indicador del verbo de comando por uno o más <blank>s; Las implementaciones pueden permitir la separación cero como una extensión.

    • Comando verbos que no sea {, a, b, c, i, r, t, w, :, y #puede ser seguido por un ;punto y coma, opcional <blank>s, y otro verbo de comando. Sin embargo, cuando el sverbo de comando se usa con la wbandera, seguirlo con otro comando de esta manera produce resultados indefinidos.

...en...

  • Opciones: se pueden especificar múltiples -ey -fopciones. Todos los comandos se agregarán al script en el orden especificado, independientemente de su origen.

    • -e script : agregue los comandos de edición especificados por el argumento de opción de script al final del script de comandos de edición. El argumento de opción de script tendrá las mismas propiedades que el operando del script , descrito en la sección OPERANDS .

    • -f script_file : agrega los comandos de edición en el archivo script_file al final del script.

Y último en ...

  • Operandos:

    • script : una cadena que se utilizará como script de los comandos de edición. La aplicación no debe presentar un guión que viole las restricciones de un archivo de texto, excepto que el carácter final no necesita ser una línea \nelectrónica.

Entonces, cuando lo toma en conjunto, tiene sentido que cualquier comando que esté opcionalmente seguido de un parámetro arbitrario sin un delimitador predefinido (en oposición a, s d sub d repl d flagpor ejemplo) se delimite en una línea de escape sin escape \n.

Es discutible que ; sea un delimitador predefinido, pero en ese caso el uso ;de cualquiera de los [aic]comandos requeriría que se incluyera un analizador por separado en la implementación específicamente para esos tres comandos [:brw], por ejemplo , separado del analizador utilizado . O de lo contrario, la implementación tendría que requerir que ; también se escape la barra invertida dentro del parámetro de texto y solo se vuelva más complicado a partir de ahí.

Si yo estuviera escribiendo una sedque anhelaba ser a la vez compatible y eficiente, entonces yo no escribiría un programa de análisis tales separada, espero que - a excepción de que tal vez [aic]deberían generación de un error de sintaxis si no es seguido inmediatamente por un \newline. Pero ese es un problema de tokenización simple: el caso del delimitador final es generalmente el más problemático. Simplemente lo escribiría así:

sed -e w\ file\\ -e one -e '...;and more commands'

...y...

sed -e a\\ -e appended\\ -e text -e '...;and more commands'

... se comportaría de manera muy similar, ya que el primero crearía y escribiría en un archivo llamado:

file
one

... y el segundo agregaría un bloque de texto a la línea actual en la salida como ...

appended
text

... porque ambos compartirían el mismo código de análisis para el parámetro.

Y con respecto al tema { ... }y $!, bueno, estaba lejos. Un solo comando precedido por una dirección no es una función, sino que es solo un comando direccionado. Casi todos los comandos, incluida la { definición de funciones, } se especifican para aceptar /one/o /one/,/two/direcciones, con la excepción de la definición de #comentarios y :etiquetas . Y una dirección puede ser un número de línea o un expreso regular y se puede negar con !. Entonces todos ...

$!d
/address/s/ub/stitution/
5!y/d/c/

... puede ir seguido de uno ;y más comandos de acuerdo con el estándar, pero si se requieren más comandos para una sola dirección, y esa dirección no debe reevaluarse después de la ejecución de cada comando, entonces se debe usar una {función }como:

/address/{ s//replace addressed pattern/
           s/do other conditional/substitutions/
           s/in the same context/without/
           s/reevaluating/address/
}

... donde {no se puede seguir en la misma línea un cierre }y ese cierre }no puede ocurrir excepto al comienzo de una línea. Pero si un comando contenido no debería ser seguido por una línea \nelectrónica, entonces tampoco necesita dentro de la función. Por lo tanto, todas las s///sustituciones anteriores , e incluso la }llave de cierre , pueden seguirse de forma portátil con ;punto y coma y otros comandos.

Sigo hablando de \ndelimitadores ewline, pero la pregunta es sobre -elas declaraciones de xpression, lo sé. Pero los dos son realmente uno y lo mismo, y la relación clave es que un script puede ser un argumento de línea de comandos literal o un archivo con cualquiera de los dos -[ef], y que ambos se interpretan como archivos de texto (que se especifican para terminar en un \newline) pero ninguna de las dos tiene que terminar en \newline. Con esto puedo deducir razonablemente (espero) que un \0NULargumento delimitado implica una línea de \new final , y como todos los argumentos de invocación obtienen al menos) un \0NULdelimitador de todos modos, entonces cualquiera debería funcionar bien.

De hecho, en la práctica, en todos los casos, excepto uno en el que el estándar especifica \que se requiere una barra invertida con escape de nueva línea, he encontrado ...

sed -e ... -e '...\' -e '...'

... para trabajar igual de bien. Y en todos los casos, una vez más, en la práctica, en los \nque se debe requerir una línea electrónica sin escape ...

sed -e '...' -e '...'

... también ha funcionado para mí. La única excepción que menciono arriba es ...

sed -e 's/.../...\' -e '.../'

... que no funciona para ninguna implementación en ninguna de mis pruebas. Estoy bastante seguro de que eso se remonta al requisito del archivo de texto y al hecho de que s/// viene con un delimitador y, por lo tanto, no hay ninguna razón para que una sola declaración abarque \0NULargumentos delimitados.

Entonces, en conclusión, aquí hay un breve resumen de formas portátiles de escribir varios tipos de sedcomandos:

Para cualquiera de [aic]:

...commands;[aic]\
text embedded newline\
delimiting newline
...more;commands...

...o...

sed -e '...commands;[aic]\' -e 'text embedded newline\' -e 'delimiting newline' -e '.;.;.'

Para cualquiera de [:rwtb]donde el parámetro es opcional (para todos menos :), pero la línea de delimitación no lo\n es . Tenga en cuenta que nunca he tenido una razón para tratar de varias líneas de etiqueta parámetros que se utilizaría con , pero que riting / LECTURA a varias líneas en [RW] archivo de parámetros se acepta generalmente sin lugar a dudas por s He probado tanto tiempo como el incrustado ewline se escapa con una barra invertida. Aún así, el estándar no especifica directamente que la etiqueta y los parámetros del archivo [rw] deben analizarse de manera idéntica al texto[:tb]wrsed\n\parámetros y no hace mención de \newlines con respecto a los dos primeros, excepto porque los delimita.

...commands;[:trwb] parameter
...more;commands...

...o...

sed -e '[:trwb] parameter' -e '...'

... donde lo <space>anterior es opcional para [:tb].

Y última...

...;address[!]{ ...function;commands...
};...more;commands....

...o...

sed -e '...;address[!]{ ...function;commands...' -e '};...more;commands...'

... donde cualquiera de los comandos antes mencionados (excepto :) también acepta al menos una dirección y que puede ser una /expresión regular /o un número de línea y podría negarse !, pero si se necesita más de un comando para una sola evaluación de la dirección, entonces {Se }deben utilizar llaves de delimitación de contexto de función . Una función puede contener incluso múltiples \ncomandos delimitados por ewline, pero cada uno debe estar delimitado dentro de las llaves como lo sería de otra manera.

Y así es como escribir sedscripts portátiles .


2
¿Por qué no aceptas tu propia respuesta?
Philippos
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.