Me parece que \n
no 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, ¡ \n
no 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!
echo "foo bar" | tr ' ' '\n'
\n
.Respuestas:
Puede
brew install gnu-sed
y reemplazar llamadassed
congsed
.Si no desea anteponer la "g" a
sed
, puedebrew install gnu-sed --with-default-names
y simplemente llamesed
.(Editar: bandera de cerveza actualizada, punta de sombrero a Clément)
fuente
--with-default-names
y no--default-names
. Sin embargo, esta opción no funcionó en mi instalación, por lo que tuve que poner unaalias gsed=sed
en mi~/.profile
para que funcione.sed
en OS X se comporta de la manera en que lo hace y hace una suposición incorrecta quegnu-sed
es más correcta. No sea un adicto a GNU y cumpla con los estándares POSIX para evitar problemas a largo plazo.Estos también funcionarían:
echo 'foo bar' | sed $'s/ /\\\n/g'
lf=$'\n'; echo 'foo bar' | sed "s/ /\\$lf/g"
El sed de OS X no se interpreta
\n
en 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.fuente
sed $'s/ /\\\n/g'
funciona, pero nosed $'s/\\\n/ /g'
?sed
incluso 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//'
La solución alternativa que encontró pasa una cadena de argumento único a
sed -e
.Ese argumento termina siendo una cadena en el
s/ / /g
formato 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.]
fuente
La expresión
$'...'
es unbash
-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 ess/ /\
. (Sí, puede cambiar las comillas en el medio de una cadena; no termina la cadena).El estándar POSIX
sed
solo acepta\n
como parte de un patrón de búsqueda. OS X usa FreeBSDsed
, 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).fuente
$'...'
parte. Pero ... que ess/ /\
? ¿Qué quieres decir conswitch quoting
?'...'
es un tipo de citación de shell;$'...'
es otro. También hay"..."
y\x
para 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 unsed
comando (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/g
espacios (la bandera) con nuevas líneas.Hay una manera muy fácil de ver visualmente lo que está sucediendo. ¡Simplemente repita la secuencia!
resultados en
que es equivalente a
s/$/\
newline/g
Si no tenía el extra
\
antes delnewline
, el shell interpretaríanewline
el final prematuramente del comando.fuente