sed
BSD / macOS Sed vs. GNU Sed vs. la especificación POSIX Sed
Buscar..
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).
- Advertencia: GNU
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
sí 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.
- Secuencias de caracteres de control como
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.
- BSD
-i
sensiblemente activa la numeración de línea por archivo de entrada en GNUsed
y las versiones recientes de BSDsed
(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.
- BSD
Características comunes :
- Si restringe sus scripts
sed
a lo que soporta BSDsed
, por lo general, también funcionarán en GNUsed
, 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.
- Si restringe sus scripts
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 GNUsed
admite (a menos que se use--posix
), BSDsed
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 ) (GNUsed
no documenta-E
, pero funciona como un alias de-r
; versión más reciente de BSDsed
, 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óns
), porque BSDsed
no las admite en expresiones regulares extendidas (pero, curiosamente, lo hace en Los básicos , donde están obligados por POSIX).
- aserciones de límite de palabra, porque son específicas de la plataforma (por ejemplo,
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 usandoprintf
(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
- Sólo Linux:
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'
- Sólo Linux:
Lo mismo ocurre con los argumentos de texto a la
i
ya
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
yt
, 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'
- O (nuevas líneas reales):
- Sólo Linux:
Funciones
i
ya
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) .
- Sin
- Sólo Linux:
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'
-
- Sólo Linux:
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, BSDsed
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
- La opción
Secuencias de escape
Secuencias de escape relacionadas con la sustitución como
\u
en el argumento de reemplazo de la funcións///
que permite la manipulación de subcadenas , dentro de los límites; por ejemplo,sed 's/^./\u&/' <<<'dog' # -> 'Dog'
- vea http://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022 -MandoSecuencias de escape de caracteres de control: además de
\n
,\t
, ..., escapes basados en puntos de código; por ejemplo, todos los escapes siguientes (hex., octal, decimal) representan una comilla simple ('
):\x27
,\o047
,\d039
- vea https://www.gnu.org/software/sed/manual/ sed.html # Escapes
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 deaddr
, ... - 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'']
Reemplazar todas las nuevas líneas con pestañas
Nota: para mayor brevedad, los comandos utilizan aquí cadenas ( <<<
) y cadenas ANSI entre comillas ( $'...'
) . Estas dos funciones de shell funcionan en bash
, ksh
y zsh
.
# GNU Sed
$ sed ':a;$!{N;ba}; s/\n/\t/g' <<<$'line_1\nline_2\nline_3'
line_1 line_2 line_3
# BSD Sed equivalent (multi-line form)
sed <<<$'line_1\nline_2\nline_3' '
:a
$!{N;ba
}; s/\n/'$'\t''/g'
# BSD Sed equivalent (single-line form, via separate -e options)
sed -e ':a' -e '$!{N;ba' -e '}; s/\n/'$'\t''/g' <<<$'line 1\nline 2\nline 3'
Notas de BSD Sed:
Tenga en cuenta la necesidad de terminar las etiquetas (
:a
) y los comandos de bifurcación (ba
) con nuevas líneas reales o con opciones-e
separadas.Dado que las secuencias de escape de caracteres de control como
\t
no son compatibles con la cadena de reemplazo, se empalma un literal de tabulación ANSI con comillas en la cadena de reemplazo.
(En la parte de expresiones regulares , BSD Sed solo reconoce\n
como una secuencia de escape).
Agregar texto literal a una línea con la función 'a'
Nota: para mayor brevedad, los comandos utilizan aquí cadenas ( <<<
) y cadenas ANSI entre comillas ( $'...'
) . Estas dos funciones de shell funcionan en bash
, ksh
y zsh
.
# GNU Sed
$ sed '1 a appended text' <<<'line 1'
line 1
appended text
# BSD Sed (multi-line form)
sed '1 a\
appended text' <<<'line 1'
# BSD Sed (single-line form via a Bash/Ksh/Zsh ANSI C-quoted string)
sed $'1 a\\\nappended text' <<<'line 1'
Observe cómo BSD Seed requiere un \
seguido de una nueva línea real para pasar el texto para agregar.
Lo mismo se aplica a las funciones relacionadas i
(insertar) c
(eliminar e insertar).