sed no me proporciona una operación sustituta correcta para la nueva línea con Mac: diferencias entre GNU sed y BSD/OSX sed [duplicado]
Estoy usando esta referencia: ayuda sed: hacer coincidir y reemplazar un literal "\n" (no la nueva línea)
y tengo un archivo "test1.txt" que contiene una cadena hola\nadiós
Utilizo este comando para buscar y reemplazar "\n" con caracteres de nueva línea reales:
sed -i '' 's/\\n/\n/g' test1.txt
pero el resultado es: hola, adiós . simplemente reemplaza "\n" con "n" y no una nueva línea real. Esto hace lo mismo con /t donde dejará una "t" y no una pestaña.
el '' es para el error indefinido en MAC: http://mpdaugherty.wordpress.com/2010/05/27/difference-with-sed-in-place-editing-on-mac-os-x-vs-linux /
Actualizar :
Probé los dos comandos que sugirió @ hek2mgl:
sed -i 's/\\n/\n/g' test.txt
# Or:
sed -i'' 's/\\n/\n/g' test.txt
Si bien es posible que funcionen con Linux, con MAC OS recibí el siguiente error:
sed: 1: "test1.txt": undefined label 'est1.txt'
No estoy seguro de por qué no puedo hacer que esto funcione. Gracias de antemano.
Con BSD/macOS sed
, para usar una nueva línea en la cadena de reemplazo de una s
llamada de función, debe usar una nueva línea real\
con escape ; la secuencia de escape no\n
se admite allí (a diferencia de la parte de expresión regular de la llamada).
Ya sea : simplemente inserte una nueva línea real :
sed -i '' 's/\\n/\ /g' test1.txt
O : utilice una cadena ANSI entre comillas C (
$'...'
) para empalmar la nueva línea ($'\n'
; funciona enbash
,ksh
ozsh
):sed -i '' 's/\\n/\'$'\n''/g' test1.txt
GNU sed
, por el contrario, sí reconoce \n
cadenas de reemplazo; Siga leyendo para obtener una descripción general completa de las diferencias entre estas dos implementaciones.
Diferencias entre GNU sed
(Linux) y BSD/macOSsed
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 POSIX .sed
El enfoque más portátil es utilizar únicamente funciones POSIX , lo que, sin embargo, limita la funcionalidad :
- En particular, POSIX especifica soporte solo para expresiones regulares básicas , que tienen muchas limitaciones (por ejemplo, no admiten
|
(alternancia) en absoluto, no admiten directamente+
y?
) y diferentes requisitos de escape.- Advertencia: GNU
sed
(sin-r
), admite\|
y\+
, que NO es compatible con\?
POSIX; Úselo--posix
para desactivar (ver más abajo).
- Advertencia: GNU
- Para utilizar únicamente las funciones POSIX :
- (ambas versiones): use solo las opciones
-n
y-e
(en particular, no use o-E
active-r
la compatibilidad con expresiones regulares extendidas ) - GNU
sed
: agregue una opción--posix
para garantizar la funcionalidad solo de POSIX (no es estrictamente necesario, pero sin ella podría terminar usando sin darse cuenta funciones que no son POSIX sin darse cuenta; advertencia :--posix
en sí mismo no es compatible con POSIX) - El uso de funciones exclusivas de POSIX implica requisitos de formato más estrictos (renunciando a muchas comodidades disponibles en GNU
sed
):- Las secuencias de caracteres de control como
\n
y\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 una continuación a través de una opción separada-e
. - Consulte a continuación para obtener más detalles.
- Las secuencias de caracteres de control como
- (ambas versiones): use solo las opciones
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 admitir AMBAS plataformas (discusión de diferencias):
- Funciones
incompatibles :
- El uso de la
-i
opción sin argumento (actualización local sin copia de seguridad) es incompatible:- BSD
sed
: DEBE usarse-i ''
- GNU
sed
: DEBE usar solo-i
(equivalente:)-i''
; el uso-i ''
NO funciona.
- BSD
-i
activa con sensatez la numeración de líneas por archivo de entrada en GNUsed
y versiones recientes de BSDsed
(por ejemplo, en FreeBSD 10), pero NO lo hace en macOS a partir de 10.15 .
Tenga en cuenta que, en ausencia de-i
todas las versiones, las líneas numéricas se acumulan en los archivos de entrada.- Si la última línea de entrada no tiene una nueva línea al 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, añade una nueva línea sólo si la línea de entrada termina en una.
- BSD
- El uso de la
- Características comunes :
- Si restringe sus
sed
scripts a lo que admite BSDsed
, generalmente también funcionarán en GNUsed
, con la notable excepción del uso de funciones de expresiones regulares extendidas-E
específicas de la plataforma con . Obviamente, también renunciará a las extensiones específicas de la versión GNU. Consulte la siguiente sección.
- Si restringe sus
Directrices para soporte multiplataforma (macOS/BSD, Linux), impulsadas por los requisitos más estrictos de la versión BSD :
Tenga en cuenta que estoy usando las abreviaturas macOS y Linux para las versiones BSD y GNU respectivamente sed
porque son las versiones estándar en cada plataforma. Sin embargo, es posible instalar GNU sed
en macOS, por ejemplo, usando Homebrew con brew install gnu-sed
.
Nota : Excepto cuando se utilizan los indicadores -r
y-E
( expresiones regulares extendidas ), las instrucciones siguientes equivalen a escribir scripts compatibles con POSIX . sed
- Para cumplir con POSIX, debe limitarse a POSIX BRE ( expresiones regulares básicas ) , que, desafortunadamente, como sugiere el nombre, son bastante básicas.
Advertencia : no asuma que\|
,\+
y\?
son compatibles: si bien GNUsed
los admite (a menos--posix
que se use), BSDsed
no; estas características no son compatibles con POSIX.
Mientras que\+
y se\?
puede emular de manera compatible con POSIX:
\{1,\}
for\+
,
\{0,1\}
for\?
,
\|
(alternación) no , desafortunadamente. Para expresiones regulares más potentes, utilice
-E
(en lugar de-r
) para admitir ERE ( expresiones regulares extendidas ) (GNUsed
no documenta-E
, pero funciona allí como un alias de-r
; la versión más reciente de BSDsed
, como en FreeBSD 10, ahora también admite-r
, pero la versión de macOS a partir de 10.10 no ).
Advertencia : aunque el uso de-r
/-E
significa que su comando, por definición, no es compatible con POSIX, aún debe restringirse a POSIX ERE (expresiones regulares extendidas) . Lamentablemente, esto significa que no podrá utilizar varias construcciones útiles, en particular:- aserciones de límites de palabras, porque son específicas de la plataforma (por ejemplo,
\<
en Linux,[[:<]]
en OS X). - referencias hacia atrás dentro de expresiones regulares (a diferencia de las "referencias hacia atrás" para capturar coincidencias de grupos en la cadena de reemplazo de
s
llamadas a funciones), porque BSDsed
no las admite en expresiones regulares extendidas (pero, curiosamente, sí lo hace en las básicas ). , donde tienen mandato POSIX).
- aserciones de límites de palabras, 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 de selección como en el primer argumento de la
s
función), supongamos que solo\n
se reconoce como una secuencia de escape (rara vez se usa, ya que el espacio del patrón suele ser una sola línea (sin terminar\n
), pero no dentro de una clase de carácter. , de modo que, por ejemplo,[^\n]
no funciona; (si su entrada no contiene caracteres de control distintos de\t
, puede emular[^\n]
con[[:print:][:blank:]]
; de lo contrario, empalme los caracteres de control como literales [2] ) - generalmente, incluya caracteres de control como literales , ya sea mediante cadenas ANSI C entrecomilladas (por ejemplo,$'\t'
) en shells que lo admiten (bash,
ksh,zsh
), o mediante sustituciones de comandos usandoprintf
(por ejemplo,"$(printf '\t')"
) .- Sólo Linux:
sed 's/\t/-/' <<<$'a\tb' # -> 'a-b'
- MacOS 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
s
comando, suponga que NO se admiten secuencias de escape de caracteres de control , por lo que, nuevamente, incluya caracteres de control. como literales , como arriba.- Sólo Linux:
sed 's/-/\t/' <<<$'a-b' # -> 'a<tab>b'
sed 's/-/\n/' <<<$'a-b' # -> 'a<newline>b'
- macOS y Linux:
sed 's/-/'$'\t''/' <<<'a-b'
sed 's/-/'"$(printf '\t')"'/' <<<'a-b'
sed 's/-/\'$'\n''/' <<<'a-b'
tenga en cuenta que las nuevas líneas deben tener una barra invertida para que se interpreten correctamente como parte de la cadena de reemplazo y no como el final del comando, y que el usoprintf
no funciona para las nuevas líneas ya que las nuevas líneas finales se eliminan mediante sustituciones de comandos. ($(...)
).
- Sólo Linux:
Lo mismo ocurre con los argumentos de texto de las funciones
i
ya
: no utilice secuencias de caracteres de control ; consulte a continuación.
- En las expresiones regulares (tanto en los patrones de selección como en el primer argumento de la
- Etiquetas y bifurcaciones : las etiquetas, así como el argumento
b
del nombre de la etiqueta de last
funciones y deben ir seguidos de una nueva línea literal o de un empalme$'\n'
. Alternativamente, use múltiples-e
opciones 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:
- CUALQUIERA (nuevas líneas reales):
sed -n '/a/ bLBL d; :LBL p' <<<$'a\nb'
- O (instancias empalmadas
$\n
):
sed -n '/a/ bLBL'$'\n''d; :LBL'$'\n''p' <<<$'a\nb'
- O (múltiples
-e
opciones):
sed -n -e '/a/ bLBL' -e 'd; :LBL' -e 'p' <<<$'a\nb'
- CUALQUIERA (nuevas líneas reales):
- Sólo Linux:
- Funciones
i
ya
para insertar/añadir texto : siga el nombre de la función por\
, seguido de una nueva línea literal o un empalme$'\n'
antes de especificar el argumento de texto.- Sólo Linux:
sed '1 i new first line' <<<$'a\nb' # -> 'new first line<nl>a<nl>b'
- MacOS y Linux:
sed -e '1 i\'$'\n''new first line' <<<$'a\nb'
- Nota:
- Sin
-e
, el argumento de texto inexplicablemente no termina en una nueva línea en la salida en macOS (¿error?). - No utilice escapes de caracteres de control como
\n
y\t
en el argumento de texto, ya que solo se admiten en Linux. - Por lo tanto, si el argumento del texto tiene nuevas líneas interiores reales,
\
escápelas. - Si desea colocar comandos adicionales después del argumento de texto, debe terminarlo con una nueva línea (sin escape) (ya sea literal o intercalada) o continuar con una
-e
opción 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 funciones encerradas en
{...}
), asegúrese de finalizar 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'
Con la
-f
opción (para leer comandos de un archivo), solo GNUsed
admite-
como marcador de posición para stdin; utilícelo-f /dev/stdin
para leer comandos de forma portátil desde stdin , incluidos los de here-documents (suponiendo que su plataforma lo admita/dev/stdin
, lo que suele ser el caso hoy en día).
sed
Características específicas de GNU que faltan por completo en BSD sed
:
Funciones de GNU que se perderá si necesita admitir ambas plataformas:
Varias opciones de sustitución y coincidencia de expresiones regulares (tanto en patrones para la selección de línea como en el primer argumento de la
s
función):- La
I
opción para la coincidencia de expresiones regulares que distinguen entre mayúsculas y minúsculas (increíblemente, BSDsed
no admite esto en absoluto). - La
M
opción de coincidencia de varias líneas (donde^
/$
coincide con el inicio/final de cada línea ) - Para opciones adicionales que son específicas de la
s
función, consulte https://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command
- La
Secuencias de escape
Secuencias de escape relacionadas con la sustitución, como
\u
en el argumento de reemplazo de las///
función, que permiten la manipulación de subcadenas , dentro de límites; por ejemplo,sed 's/^./\u&/' <<<'dog' # -> 'Dog'
consulte http://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-CommandSecuencias de escape de caracteres de control: además de
\n
,\t
, ..., escapes basados en puntos de código; por ejemplo, todos los siguientes escapes (hex., octal, decimal) representan una comilla simple ('
):\x27
,\o047
,\d039
- consulte https://www.gnu.org/software/sed/manual/sed.html#Escapes
Extensiones de dirección , como
first~step
para hacer coincidir cada paso de línea,addr, +N
para hacer coincidir N líneas siguientesaddr
, ... - consulte http://www.gnu.org/software/sed/manual/sed.html#Addresses
[1] La sed
versión de macOS es anterior a la versión de otros sistemas similares a BSD, como FreeBSD y PC-BSD. Desafortunadamente, esto significa que no se puede asumir que las características que funcionan en FreeBSD, por ejemplo, funcionarán [igualmente] en macOS.
[2] La cadena ANSI entre comillas C $'\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 puedes usarla en combinación con [:print:]
para una emulación bastante sólida 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'']
Esto puede parecer un poco extraño, pero intenta:
sed -i '' 's/\\n/\
/g' test1.txt
Es decir, utilice una nueva línea real en lugar de \n
.
¡La explicación es que tienes un extraño sed
! Para obtener más información, consulte el manual de mac sed: https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/sed.1.html
En la descripción del s
comando allí, dice:
A line can be split by substituting a newline character into it. To specify
a newline character in the replacement string, precede it with a backslash.
Además, en la descripción de la -i
opción, dice que la extensión no es opcional y que si no quieres una debes especificar un argumento vacío. ¡Así que al final todo tiene sentido!