Nouvelles lignes dans sed sur Mac OS X

44

Je trouve que \ncela ne fonctionne pas dans sed sous Mac OS X. Plus précisément, disons que je veux séparer les mots séparés par un seul espace en lignes:

# input
foo bar

J'utilise,

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

Mais le résultat est stupide, le \nn'est pas échappé!

foonbar

Après avoir consulté Google, j'ai trouvé une solution de contournement :

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

Après avoir lu l'article, je ne comprends toujours pas ce que \'$'\n/g'signifie. Quelqu'un peut-il me l'expliquer ou s'il existe un autre moyen de le faire? Merci!

Ivan ZG Xiao
la source
cela fonctionnerait probablement aussi:echo "foo bar" | tr ' ' '\n'
glenn jackman
3
Merci pour le conseil. Mais à l’heure actuelle, j’utilise simplement le cas ci-dessus à titre d’exemple \n.
Ivan ZG Xiao
Doublon

Réponses:

27

Vous pouvez brew install gnu-sedremplacer les appels sedavec gsed.

Si vous ne voulez pas ajouter le "g" à la fin sed, vous pouvez brew install gnu-sed --with-default-nameset simplement appeler sed.

(Edit: drapeau de brassage mis à jour, pointe de chapeau à Clément.)

Ahmed Fasih
la source
Utiliser le même logiciel sur toutes les plateformes est bien plus facile (enfin pour moi) que de traiter de toutes les spécificités de la version Mac. Attention, l'option est maintenant --with-default-nameset non --default-names . Cependant, cette option n'a pas travaillé sur mon installation, donc je devais mettre alias gsed=seddans ma ~/.profilepour le faire fonctionner.
Clément
4
Ceci est une solution de contournement laide. Cela n'explique pas pourquoi sedsur OS X se comporte comme il le fait et fait l'hypothèse incorrecte qui gnu-sedest plus correcte. Ne soyez pas un dépendant de GNU et respectez les normes POSIX pour éviter les problèmes à long terme.
octosquidopus
C'est ainsi que Apple devrait faire fonctionner son système d'exploitation par défaut. Pourquoi utiliser le nom d'un programme et ensuite le faire fonctionner différemment? Je
perds
@rascio - car OS X est semblable à BSD et Linux à Linux.
iAdjunct
@ rascio Je pense que vous constaterez que GNU sed est le nouveau venu; BSD sed date de 1979 (voir en.wikipedia.org/wiki/Version_7_Unix ).
Duncan Bayne
24

Ceux-ci fonctionneraient également:

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

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

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

Sed d'OS X n'interprète pas \nle motif de remplacement, mais vous pouvez utiliser un saut de ligne littéral précédé d'un caractère de continuation de ligne. Le shell est remplacé $'\n'par un saut de ligne littéral avant l'exécution de la commande sed.

Lri
la source
4
Pourquoi sed $'s/ /\\\n/g'travaille- t-il , mais pas sed $'s/\\\n/ /g'?
Alec Jacobson
1
@alec Vous ne pouvez même pas utiliser sedlinux / unix pour supprimer les nouvelles lignes car elles sont analysées / divisées à chaque nouvelle ligne. Si vous utilisez ceci sous linux / unix, cela ne fera rien non plus:echo -e 'foo\nbar' | sed 's/\n//'
wisbucky
10

La solution de contournement trouvée passe une chaîne d'argument unique sed -e.

Cet argument finit par être une chaîne dans le s/ / /gformat sed habituel .

Cette chaîne est créée en deux parties, l'une après l'autre.

La première partie est citée dans la '...'forme.

La deuxième partie est citée dans la $'...'forme.

La 's/ /\'partie supprime les guillemets simples, mais passe sinon à sed, telle qu'elle apparaît sur la ligne de commande. C'est-à-dire que la barre oblique inverse n'est pas mangée par bash, elle est transmise à sed.

La $'\n/g'partie obtient le signe dollar et les guillemets simples enlevés, puis \nest convertie en un caractère de nouvelle ligne.

Tous ensemble, l'argument devient

s / / \ newline/ g

[C'était amusant. Il a fallu du temps pour le déballer. +1 pour une question intéressante.]

Spiff
la source
7

L'expression $'...'est un bash-isme qui produit ...avec les séquences d'échappement standard étendues. Th \'avant cela signifie juste un antislash suivi d' ici la fin de la section citée, la chaîne résultante est s/ /\. (Oui, vous pouvez basculer entre guillemets au milieu d'une chaîne; cela ne termine pas la chaîne.)

La norme POSIX sedn’accepte \nque dans le cadre d’un modèle de recherche. OS X utilise FreeBSD sed, qui est strictement conforme à POSIX; Comme d’habitude, GNU ajoute des éléments supplémentaires et les utilisateurs de Linux pensent tous qu’il s’agit d’une sorte de «standard» (je serais peut-être plus impressionné si l’un d’eux avait un processus de normalisation).

geekosaur
la source
Maintenant je comprends la $'...'partie. Mais ... c'est quoi s/ /\ ? Que veux-tu dire par switch quoting?
Ivan ZG Xiao
2
'...'est un type de coquille citant; $'...'est un autre. Il y a aussi "..."et \xpour citer un seul personnage. Vous pouvez combiner ceux-ci en un seul mot, ce qui correspond à ce qui était fait ici, passant d’une ''chaîne normale à une $''chaîne pour traduire le \n. Pour le reste, il construit une sedcommande ( s/text/replacement/flags). Dans ce cas, la commande est démarrée, avec une barre oblique inverse à la fin pour protéger le retour à la ligne littéral ajouté $'\n/g'. Le résultat est de remplacer tous les /gespaces (les drapeaux) par des nouvelles lignes.
geekosaur
1

Il est très facile de voir ce qui se passe. Faites simplement écho à la corde!

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

résulte en

s/$/\
/g

ce qui équivaut à s/$/\newline/g

Si vous n'aviez pas le supplément \avant le newline, le shell interprèterait newlineprématurément la fin de la commande.

sage
la source