Looking for sed Answers? Try Ask4KnowledgeBase
Looking for sed Keywords? Try Ask4Keywords

sedBSD / macOS Sed vs. GNU Sed vs. la especificación POSIX Sed


Introducción

Para citar la solicitud de creación de tema de @SnoringFrog:

"Uno de los errores más grandes que utilizan sed son los scripts que fallan (o tienen éxito de una manera inesperada) porque fueron escritos para uno y no para el otro. La reducción simple de las diferencias más importantes sería buena".

Observaciones

macOS usa la versión BSD de sed [1] , que difiere en muchos aspectos de la versión GNU sed que viene con las distribuciones de Linux .

Su denominador común es la funcionalidad decretada por POSIX : consulte la especificación de POSIX sed .

El enfoque más portátil es usar solo las características de POSIX , lo que, sin embargo, limita la funcionalidad :

  • En particular, POSIX especifica el soporte solo para expresiones regulares básicas , que tienen muchas limitaciones (por ejemplo, sin soporte para | (alternancia), sin soporte directo para + y ? ) Y diferentes requisitos de escape.

    • Advertencia: GNU sed (sin -r ), soporta \| , \+ y \? , que NO es compatible con POSIX; use --posix para deshabilitar (ver más abajo).
  • Para usar solo las características POSIX :

    • (ambas versiones): use solo las opciones -n -e (en particular, no use -E o -r para activar el soporte para expresiones regulares extendidas )

    • GNU sed : añadir la opción --posix para asegurar la funcionalidad POSIX única (que no estrictamente necesario, pero sin ella podría terminar con inadvertidamente no cuenta con POSIX sin darse; salvedad: --posix no es compatible con POSIX )

    • El uso de las funciones exclusivas de POSIX implica requisitos de formato más estrictos (renunciando a muchas comodidades disponibles en GNU sed ):

      • Secuencias de caracteres de control como \n \t generalmente NO son compatibles.
      • Las etiquetas y los comandos de bifurcación (por ejemplo, b ) deben ir seguidos de una nueva línea real o continuación a través de una opción -e separada.
      • Vea a continuación para más detalles.

Sin embargo, ambas versiones implementan extensiones al estándar POSIX:

  • Las extensiones que implementan difieren (GNU sed implementa más).
  • incluso aquellas extensiones que ambos implementan difieren parcialmente en la sintaxis .

Si necesita soportar AMBAS plataformas (discusión de diferencias):

  • Características incompatibles :

    • El uso de la opción -i sin un argumento (actualización in situ sin copia de seguridad) es incompatible:

      • BSD sed : DEBE utilizar -i ''
      • GNU sed : DEBE usar solo -i (equivalente: -i'' ) - usar -i '' NO funciona.
    • -i sensiblemente activa la numeración de línea por archivo de entrada en GNU sed y las versiones recientes de BSD sed (por ejemplo, en FreeBSD 10), pero NO en macOS a partir de 10.12 .
      Tenga en cuenta que, en ausencia de -i todas las versiones numeran las líneas de forma acumulativa en los archivos de entrada.

    • Si la última línea de entrada no tiene una nueva línea final (y se imprime):

      • BSD sed : siempre agrega una nueva línea en la salida, incluso si la línea de entrada no termina en una.
      • GNU sed : conserva el estado de nueva línea final , es decir, agrega una nueva línea solo si la línea de entrada terminó en una.
  • Características comunes :

    • Si restringe sus scripts sed a lo que soporta BSD sed , por lo general, también funcionarán en GNU sed , con la notable excepción de usar características de expresiones regulares extendidas específicas de la plataforma con -E . Obviamente, también renunciará a las extensiones que son específicas de la versión GNU. Ver la siguiente sección.

Pautas para el soporte multiplataforma (OS X / BSD, Linux), impulsadas por los requisitos más estrictos de la versión BSD :

Tenga en cuenta que las abreviaturas que MacOS y Linux se utilizan de vez en cuando a continuación para referirse a las versiones BSD y GNU de sed , respectivamente, debido a que son las versiones de valores en cada plataforma. Sin embargo, es posible instalar GNU sed en macOS, por ejemplo, utilizando Homebrew con brew install gnu-sed .

Nota : Excepto cuando se usan los indicadores -r y -E (expresiones regulares extendidas ), las instrucciones a continuación equivalen a escribir scripts sed compatibles con POSIX .

  • Para cumplir con POSIX, debe restringirse a POSIX BRE (expresiones regulares básicas ) , que, desafortunadamente, como su nombre indica, son bastante básicas.
    Advertencia : no asuma que \| , \+ y \? son compatibles: mientras que GNU sed admite (a menos que se use --posix ), BSD sed no lo hace - estas características no son compatibles con POSIX.
    Mientras que \+ y \? Se puede emular de manera compatible con POSIX:
    \{1,\} para \+ ,
    \{0,1\} para \? ,
    \| (alternancia) no puede , por desgracia.

  • Para expresiones regulares más potentes, use -E (en lugar de -r ) para admitir ERE (expresiones regulares extendidas ) (GNU sed no documenta -E , pero funciona como un alias de -r ; versión más reciente de BSD sed , como en FreeBSD 10, ahora también es compatible con -r , pero la versión macOS a partir de 10.12 no lo hace).
    Advertencia : aunque el uso de -r / -E significa que su comando no es compatible con POSIX por definición, aún debe restringirse a los ERE de POSIX (expresiones regulares extendidas) . Lamentablemente, esto significa que no podrá usar varias construcciones útiles, en particular:

    • aserciones de límite de palabra, porque son específicas de la plataforma (por ejemplo, \< en Linux, [[:<]] en OS X).
    • Las referencias inversas dentro de las expresiones regulares (a diferencia de las "referencias inversas" a las coincidencias del grupo de captura en la cadena de reemplazo de s llamadas de función s ), porque BSD sed no las admite en expresiones regulares extendidas (pero, curiosamente, lo hace en Los básicos , donde están obligados por POSIX).
  • Secuencias de escape de caracteres de control como \n y \t :

    • En las expresiones regulares (tanto en los patrones para la selección de líneas como en el primer argumento de la función s ), suponga que solo \n se reconoce como una secuencia de escape (que se usa raramente, ya que el espacio del patrón suele ser una sola línea (sin terminar \n ), pero no dentro de una clase de caracteres , por lo que, por ejemplo, [^\n] no funciona; (si su entrada no contiene caracteres de control. aparte de \t , puede emular [^\n] con [[:print:][:blank:]] ; de lo contrario, empalme los caracteres de control en como literales [2] ) - generalmente, incluye los caracteres de control como literales , ya sea a través de cadenas citadas con ANSI C empalmadas (por ejemplo, $'\t' ) en shells que lo soportan ( bash, ksh, zsh ), o mediante sustituciones de comandos usando printf (por ejemplo, "$(printf '\t')" ) .

      • Sólo Linux:
        sed 's/\t/-/' <<<$'a\tb' # -> 'a-b'
      • OSX y Linux:
        sed 's/'$'\t''/-/' <<<$'a\tb' # ANSI C-quoted string
        sed 's/'"$(printf '\t')"'/-/' <<<$'a\tb' # command subst. with printf
    • En las cadenas de reemplazo utilizadas con el comando s , suponga que NO se admiten las secuencias de escape de control-caracteres , por lo que, nuevamente, incluyen caracteres de control. Como literales , como los anteriores.

      • Sólo Linux:
        sed 's/-/\t/' <<<$'ab' # -> 'a<tab>b'
      • macOS y Linux:
        sed 's/-/'$'\t''/' <<<'a-b'
        sed 's/-/'"$(printf '\t')"'/' <<<'a-b'
    • Lo mismo ocurre con los argumentos de texto a la i y a funciones: no utilizar secuencias de control de caracteres - véase más abajo.

  • Etiquetas y bifurcaciones : las etiquetas, así como el argumento de nombre de etiqueta para las funciones b y t , deben ir seguidas de una línea nueva literal o de $'\n' empalmados . Alternativamente, use múltiples opciones -e y termine cada una justo después del nombre de la etiqueta.

    • Sólo Linux:
      sed -n '/a/ bLBL; d; :LBL p' <<<$'a\nb' # -> 'a'
    • macOS y Linux:
      • O (nuevas líneas reales):
        sed -n '/a/ bLBL d; :LBL p' <<<$'a\nb'
      • O (instancias empalmadas en $\n ):
        sed -n '/a/ bLBL'$'\n''d; :LBL'$'\n''p' <<<$'a\nb'
      • O (múltiples opciones -e ):
        sed -n -e '/a/ bLBL' -e 'd; :LBL' -e 'p' <<<$'a\nb'
  • Funciones i y a para insertar / agregar texto : siga el nombre de la función por \ , seguido de una nueva línea literal o un empalmado $'\n' antes de especificar el argumento del texto.

    • Sólo Linux:
      sed '1 i new first line' <<<$'a\nb' # -> 'new first line<nl>a<nl>b'
    • OSX y Linux:
      sed -e '1 i\'$'\n''new first line' <<<$'a\nb'
    • Nota:
      • Sin -e , el argumento de texto no es inexplicablemente terminado en una nueva línea en la salida en macOS (bug?).
      • No utilice escapes de caracteres de control como \n \t en el argumento de texto, ya que solo son compatibles con Linux.
      • Si el argumento de texto, por lo tanto, tiene nuevas líneas interiores reales, \ -escape ellas.
      • Si desea colocar comandos adicionales después del argumento de texto, debe terminarlo con una nueva línea (no escapada) (ya sea literal o empalmada), o continuar con una opción -e separada (este es un requisito general que se aplica a todas las versiones) .
  • Dentro de las listas de funciones (múltiples llamadas a función encerradas en {...} ), asegúrese de terminar también la última función, antes del cierre } , con ; .

    • Sólo Linux:
      • sed -n '1 {p;q}' <<<$'a\nb' # -> 'a'
    • macOS y Linux:
      • sed -n '1 {p;q;}' <<<$'a\nb'

Características específicas de GNU sed que faltan en BSD sed completo:

Las características de GNU que se perderán si necesita soportar ambas plataformas:

  • Varias opciones de coincidencia de expresiones regulares y sustitución (tanto en los patrones de selección de líneas como en el primer argumento de la función s ):

    • La opción I para la coincidencia de expresiones regulares con mayúsculas y minúsculas (increíblemente, BSD sed no admite esto en absoluto).
    • La opción M para la coincidencia de varias líneas (donde ^ / $ coincide con el inicio / final de cada línea )
    • Para opciones adicionales que son específicas de la función s , consulte https://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command
  • Secuencias de escape

  • Extensiones de dirección , como first~step para que coincida con cada línea de paso, addr, +N para que coincida con N líneas después de addr , ... - consulte http://www.gnu.org/software/sed/manual/sed. html # Direcciones


[1] La versión macOS sed es más antigua que la versión en otros sistemas similares a BSD como FreeBSD y PC-BSD. Desafortunadamente, esto significa que no puede asumir que las funciones que funcionan en FreeBSD, por ejemplo, funcionarán [las mismas] en macOS.

[2] La cadena de cotización ANSI $'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177' contiene todos los caracteres de control ASCII excepto \n (y NUL), por lo que puede usarlo en combinación con [:print:] para una emulación bastante robusta de [^\n] :
'[[:print:]'$'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177'']

BSD / macOS Sed vs. GNU Sed vs. la especificación POSIX Sed Ejemplos relacionados