Nuevas líneas en sed en Mac OS X

44

Me parece que \nno funciona en sed bajo Mac OS X. Específicamente, digamos que quiero dividir las palabras separadas por un solo espacio en líneas:

# input
foo bar

Yo suelo,

echo "foo bar" | sed 's/ /\n/'

Pero el resultado es estúpido, ¡ \nno se escapa!

foonbar

Después de consultar a google, encontré una solución alternativa :

echo 'foo bar' | sed -e 's/ /\'$'\n/g'

Después de leer el artículo, todavía no puedo entender lo que \'$'\n/g'significa. ¿Alguien me lo puede explicar o si hay alguna otra forma de hacerlo? ¡Gracias!

Ivan ZG Xiao
fuente
esto probablemente también funcionaría:echo "foo bar" | tr ' ' '\n'
glenn jackman
3
Gracias por el consejo. Pero actualmente solo uso el caso anterior como ejemplo, necesito saber cómo escapar de un \n.
Ivan ZG Xiao
Posible duplicado: stackoverflow.com/questions/21621722/…
hyiltiz

Respuestas:

27

Puede brew install gnu-sedy reemplazar llamadas sedcon gsed.

Si no desea anteponer la "g" a sed, puede brew install gnu-sed --with-default-namesy simplemente llame sed.

(Editar: bandera de cerveza actualizada, punta de sombrero a Clément)

Ahmed Fasih
fuente
Usar el mismo software en todas las plataformas es mucho más fácil (por fin para mí) que lidiar con todas las especificidades de la versión para Mac. Cuidado, la opción es ahora --with-default-namesy no --default-names . Sin embargo, esta opción no funcionó en mi instalación, por lo que tuve que poner una alias gsed=seden mi ~/.profilepara que funcione.
Clément
44
Esta es una solución fea. No explica por qué seden OS X se comporta de la manera en que lo hace y hace una suposición incorrecta que gnu-sedes más correcta. No sea un adicto a GNU y cumpla con los estándares POSIX para evitar problemas a largo plazo.
octosquidopus
Así es como Apple debería hacer que su sistema operativo funcione de forma predeterminada. ¿Por qué usar el nombre de un programa y luego hacer que funcione de manera diferente?
Pierdo
@rascio: porque OS X es similar a BSD y Linux es similar a Linux.
iAdjunct
@rascio Creo que encontrarás que GNU sed es el recién llegado; BSD sed se remonta a 1979 (ver en.wikipedia.org/wiki/Version_7_Unix ).
Duncan Bayne
24

Estos también funcionarían:

echo 'foo bar' | sed 's/ /\
/g'

echo 'foo bar' | sed $'s/ /\\\n/g'

lf=$'\n'; echo 'foo bar' | sed "s/ /\\$lf/g"

El sed de OS X no se interpreta \nen el patrón de reemplazo, pero puede usar un salto de línea literal precedido por un carácter de continuación de línea. El shell reemplaza $'\n'con un salto de línea literal antes de ejecutar el comando sed.

Lri
fuente
44
¿Por qué sed $'s/ /\\\n/g'funciona, pero no sed $'s/\\\n/ /g'?
Alec Jacobson el
1
@alec No puede usar sedincluso en linux / unix para eliminar nuevas líneas porque se analiza / divide en cada nueva línea. Si ejecuta esto en Linux / Unix, tampoco hará nada:echo -e 'foo\nbar' | sed 's/\n//'
wisbucky
10

La solución alternativa que encontró pasa una cadena de argumento único a sed -e.

Ese argumento termina siendo una cadena en el s/ / /gformato familiar sed .

Esa cadena se crea en dos partes, una después de la otra.

La primera parte se cita en '...'forma.

La segunda parte se cita en $'...'forma.

La 's/ /\'parte elimina las comillas simples, pero de lo contrario pasa a sed tal como se ve en la línea de comandos. Es decir, la barra invertida no se come con bash, se pasa a sed.

La $'\n/g'parte obtiene el signo de dólar y las comillas simples quitadas, y el\n se convierte en un carácter de nueva línea.

Todos juntos, el argumento se convierte

s / / \ newline/ g

[Eso fue divertido. Tomó un tiempo desenvolver eso. +1 para una pregunta interesante.]

Spiff
fuente
7

La expresión $'...'es un bash-ismo que produce ...con las secuencias de escape estándar expandidas. Th \'antes sólo significa una barra invertida seguida por el extremo de la sección citada, la cadena resultante es s/ /\. (Sí, puede cambiar las comillas en el medio de una cadena; no termina la cadena).

El estándar POSIX sedsolo acepta \ncomo parte de un patrón de búsqueda. OS X usa FreeBSD sed, que es estrictamente compatible con POSIX; GNU, como de costumbre, agrega cosas adicionales y luego los usuarios de Linux piensan que es algún tipo de "estándar" (tal vez estaría más impresionado si alguno de ellos tuviera un proceso de estándares).

geekosaur
fuente
Ahora entiendo la $'...'parte. Pero ... que es s/ /\ ? ¿Qué quieres decir con switch quoting?
Ivan ZG Xiao
2
'...'es un tipo de citación de shell; $'...'es otro. También hay "..."y \xpara citar un solo personaje. Puede combinarlos en una sola palabra, que es lo que se estaba haciendo allí, cambiando de una ''cadena normal a una $''cadena para traducir el \n. En cuanto al resto, está construyendo un sedcomando ( s/text/replacement/flags). En este caso, se inicia el comando, que incluye una barra diagonal inversa al final para proteger la nueva línea literal que se $'\n/g'agrega. El resultado es reemplazar todos los /gespacios (la bandera) con nuevas líneas.
geekosaur
1

Hay una manera muy fácil de ver visualmente lo que está sucediendo. ¡Simplemente repita la secuencia!

echo 's/$/\'$'\n/g'

resultados en

s/$/\
/g

que es equivalente a s/$/\newline/g

Si no tenía el extra \antes del newline, el shell interpretaría newlineel final prematuramente del comando.

wisbucky
fuente