¿Diferencias entre sed en Mac OSX y otros sed "estándar"?

Respuestas:

43

El comportamiento de las utilidades de shell difiere en formas menores entre las variantes de Unix. Hay muchas variantes de Unix , con una historia compleja . Existen esfuerzos de estandarización , como el estándar POSIX y su superconjunto, la especificación Single UNIX . Actualmente, la mayoría de los sistemas implementan POSIX: 2001, también conocida como Single UNIX Specification versión 3 , con pequeñas desviaciones y muchas extensiones. La especificación Single Unix no es un tutorial, pero la versión 3 es legible si ya tiene una idea de lo que está haciendo un comando. Puede consultarlo para saber si alguna característica es estándar o una extensión de un sistema en particular.

La mayoría de los usuarios de Unix usan Linux y no han usado ninguna otra variante. Linux viene con utilidades GNU , que a menudo tienen muchas extensiones al estándar. Por lo tanto, encontrará una gran cantidad de código que funciona en Linux pero no en otros dispositivos, ya que se basa en esas extensiones.

Con respecto a sed, consulte la especificación de Single Unix de sed para conocer el mínimo que se supone que debe admitir cada sistema, la página de manual de su sistema para saber qué admite su implementación y el manual de sed de GNU para lo que utiliza la mayoría de las personas.

Una de las extensiones no estándar en GNU sed es compatible con múltiples comandos que se ejecutan juntos. Por ejemplo, esta sed de GNU programa imprime todas las líneas que contienen una a, pero los cambios ben cprimer lugar:

sed -ne '/a/ {s/b/c/g; p}'

{y en }realidad son comandos separados, por lo que para una portabilidad total, debe especificarlos en líneas separadas (en un archivo) o en -eargumentos separados (en la línea de comandos). La falta de un separador de comandos después {y el uso de ;un separador de comandos son extensiones comunes. La falta de un separador de comandos antes }es una extensión menos común. Esto cumple con los estándares:

sed -n -e '/a/ {' -e 's/b/c/g' -e p -e '}'

Esto no es estándar pero es comúnmente aceptado:

sed -ne '/a/ { s/b/c/g; p; }'

Otra extensión no estándar pero común es el uso de \nsignificar una nueva línea en un stexto de reemplazo (el uso en una expresión regular es estándar). El método portátil es incluir la barra diagonal inversa-nueva línea en el script sed. Otra extensión común es \+, \?y \|en expresiones regulares significa uno o más, como máximo uno y alternancia; Las expresiones regulares básicas portátiles no tienen ninguno de estos. Por ejemplo, el primer comando es una forma no portátil de reemplazar secuencias contiguas de espacios en blanco por una nueva línea; el segundo comando es un equivalente que cumple con los estándares.

sed -e 's/ \+/\n/'
sed -e 's/  */\
/'
Gilles 'SO- deja de ser malvado'
fuente
Tenga en cuenta que en todos esos casos sobre extensiones GNU, el uso no es estándar. GNU en sedsí es compatible ya que hace cosas permitidas (pero no requeridas, no especificadas) por el estándar. Hay casos en los que no es compatible y donde POSIXLY_CORRECTpuede ser útil ejecutarlo en el entorno. Al igual s/[\n]//gque con eso, debe eliminar la reacción y los ncaracteres, pero eliminar las nuevas líneas en su lugar. O el comportamiento del Ncomando en la última línea.
Stéphane Chazelas
sed -ne '/a/ { s/b/c/g; p; }'es estándar desde la edición 2016 de la norma. Siempre fue portátil. Ver austingroupbugs.net/view.php?id=944&nbn=7
Stéphane Chazelas
60

OS X actualmente viene con un archivo FreeBSD de 2005. La mayoría de las diferencias a continuación también se aplican a otras versiones de BSD.

Usos sed de OS X para usos sed -Ede ERE y GNU -r. -Ees un alias para -ren GNU sed (agregado en 4.2, no documentado hasta 4.3). Las versiones más recientes de FreeBSD y NetBSD son compatibles con ambos -Ey -r. OpenBSD sed solo es compatible -E.

-i ''funciona con OS X's sed pero no con GNU sed. -ifunciona con GNU sed, versiones recientes de NetBSD, OpenBSD sed, pero no con OS X sed. -i -efunciona con ambos, pero en el caso de FreeBSD sedrealiza una copia de seguridad del archivo original junto -econ el nombre del archivo (y no necesita pasar más de una expresión sed).

GNU interpreta sed secuencias de escape como \t, \n, \001, \x01, \w, y \b. OS X's sed y POSIX sed solo interpretan \n(pero no en la parte de reemplazo de s).

GNU sed interpreta \|, \+y \?en BRE, pero sed de OS X y POSIX sed no. \(, \), \{, Y \}son POSIX BRE.

GNU sed permite omitir ;o una nueva línea antes, }pero sed de OS X no.

i(insert), a(append) y c(change) deben ir seguidos de una barra diagonal inversa y una nueva línea en OS X's sed y POSIX sed pero no en GNU sed. Sed de GNU añade una nueva línea faltante después del texto insertado por i, a, o csino OS X de sed no lo hace. Por ejemplo, sed 1iaes una alternativa a GNU sed $'1i\\\na\n'.

Por ejemplo, printf a|sed -n pagrega una nueva línea en sed de OS X pero no en sed de GNU.

El sistema operativo OS X no admite los modificadores I(sin distinción entre mayúsculas y minúsculas) o M(multilínea). Las versiones más recientes de soporte de sed de FreeBSD I.

El sedimento de OS X no es compatible con -s( --separate), -u( --unbuffered) o -z( --null-data).

Una opción BSD que no es compatible con GNU sed es -a, lo que hace que wanexar a un archivo en lugar de truncar un archivo.

Ejemplos de comandos de sed de GNU que no funcionan con sed de OS X:

sed /pattern/,+2d # like `sed '/pattern/{N;N;d;}'`
sed -n 0~3p # like `awk NR%3==0`
sed /pattern/Q # like `awk '/pattern/{exit}1'` or `sed -n '/pattern/,$!p'`
sed 's/\b./\u&/g' # \u converts the next character to uppercase
sed 's/^./\l&/' # \l converts the next character to lowercase
sed -i '1ecat file_to_prepend' file # e executes a shell command
sed -n l0 # 0 disables wrapping
Lri
fuente
44
-i -eno funciona en OSX. Se interpete -ecomo el sufijo.
Chris Martin
3
@ChrisMartin sí, en la versión OS X -isiempre requiere un sufijo, incluso si se trata de una cadena vacía. entonces -i '' -edebería funcionar.
waldyrious
@waldyrious Solo funciona en OSX.
Chris Martin
Sí, esa es una peculiaridad de esa versión :)
Waldyrious
3
La oración " -i -efunciona con ambos". en su respuesta sugiere que hay una solución multiplataforma. Al parecer no hay.
leondepeon
5

La mejor forma en que he encontrado que el mismo script funciona tanto en Linux como en Mac es:

sed -i.bak -e 's/foo/bar/' -- "${TARGET}" &&
  rm -- "${TARGET}.bak"
vikrantt
fuente
O use de perldónde -iviene eso . perl -Tpi -e 's/foo/bar/' -- "$TARGET"
Stéphane Chazelas