Différences entre sed sur Mac OSX et d’autres sed «standard»?

Réponses:

43

Le comportement des utilitaires shell diffère de manière mineure entre les variantes unix. Il existe de nombreuses variantes Unix , avec une histoire complexe . Il existe des efforts de standardisation tels que le standard POSIX et son sur-ensemble la spécification Single UNIX . De nos jours, la plupart des systèmes implémentent POSIX: 2001, également appelé Single UNIX Specification version 3 , avec des déviations mineures et de nombreuses extensions. La spécification Single Unix n'est pas un tutoriel, mais la version 3 est lisible si vous avez déjà une idée de ce que fait une commande. Vous pouvez le consulter pour savoir si une fonctionnalité est standard ou une extension d'un système particulier.

La majorité des utilisateurs Unix utilisent Linux et n’ont utilisé aucune autre variante. Linux est fourni avec les utilitaires GNU , qui ont souvent de nombreuses extensions du standard. Vous trouverez donc pas mal de code qui fonctionne sous Linux, mais pas sur d’autres logiciels unifiés, car il repose sur ces extensions.

En ce qui concerne sed, consultez la spécification sed Single Unix pour connaître le minimum que chaque système est supposé prendre en charge, la page de manuel de votre système pour connaître les supports pris en charge par votre implémentation, ainsi que le manuel GNU sed pour ce que la plupart des utilisateurs utilisent.

Une des extensions non standard de GNU sed supporte plusieurs commandes exécutées ensemble. Par exemple, ce programme GNU sed imprime toutes les lignes contenant un a, mais se change ben cpremier:

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

{et }sont en fait des commandes séparées. Par conséquent, pour une portabilité totale, vous devez les spécifier sur des lignes séparées (dans un fichier) ou dans des -earguments séparés (sur la ligne de commande). L'absence de séparateur de commande après {et l'utilisation de ;comme séparateur de commande sont des extensions courantes. L'absence de séparateur de commande auparavant }est une extension moins courante. Ceci est conforme à la norme:

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

Ceci est non standard mais communément accepté:

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

Une autre extension non standard mais commune est l'utilisation de \n«nouvelle ligne» dans un stexte de remplacement (l'utilisation dans une expression rationnelle est standard). La méthode portable consiste à inclure backslash-newline dans le script sed. Une autre extension courante est \+, \?et \|dans les expressions rationnelles, un ou plusieurs, au plus un et alternance; les expressions rationnelles de base portables n'en ont aucune. Par exemple, la première commande est un moyen non portable de remplacer des séquences contiguës d'espaces blancs par une nouvelle ligne; la deuxième commande est un équivalent conforme aux normes.

sed -e 's/ \+/\n/'
sed -e 's/  */\
/'
Gilles, arrête de faire le mal
la source
Notez que dans tous les cas concernant les extensions GNU, c'est l'utilisation qui n'est pas standard. GNU sedlui-même est conforme car il fait des choses autorisées (mais non requises, non spécifiées) par la norme. Il existe des cas où il n'est pas conforme et où son utilisation POSIXLY_CORRECTdans l'environnement peut aider. Comme avec s/[\n]//gcela, il faut supprimer le backlash et les ncaractères, mais supprimer les nouvelles lignes à la place. Ou le comportement de la Ncommande sur la dernière ligne.
Stéphane Chazelas
sed -ne '/a/ { s/b/c/g; p; }'est la norme depuis l'édition 2016 de la norme. C'était toujours portable. See austingroupbugs.net/view.php?id=944&nbn=7
Stéphane Chazelas
60

OS X est actuellement livré avec une version de FreeBSD sed de 2005. La plupart des différences ci-dessous s’appliquent également aux autres versions de BSD sed.

OS X utilise sed -Epour ERE et GNU sed -r. -Eest un alias pour -rdans GNU sed (ajouté dans 4.2, non documenté jusqu'à 4.3). Les nouvelles versions de FreeBSD et NetBSD sed supportent à la fois -Eet -r. OpenBSD sed ne supporte que -E.

-i ''fonctionne avec sed sous OS X mais pas sous GNU. -ifonctionne avec GNU sed, les versions récentes de NetBSD, OpenBSD sed, mais pas avec OS X sed. -i -efonctionne avec les deux, mais dans le cas de FreeBSD, il sedcrée une sauvegarde du fichier d'origine avec -ele nom de fichier ajouté (et vous ne devez pas transmettre plus d'une expression à sed).

GNU sed interprète les séquences d' échappement comme \t, \n, \001, \x01, \wet \b. OS X sed et POSIX sed n'interprètent que \n(mais pas dans la partie de remplacement de s).

GNU sed interprète \|, \+et \?en BRE, mais sed et POSIX sed d’OS X ne le font pas. \(, \), \{Et \}sont BRE Posix.

Sed de GNU autorise l’omission ;ou une nouvelle ligne auparavant, }mais pas la sed d’OS X.

i(insert), a(append), et c(change) doivent être suivis d'une barre oblique inverse et d'une nouvelle ligne dans OS X sed et POSIX sed, mais pas dans GNU sed. GNU sed ajoute une nouvelle ligne manquante après le texte inséré par i, aou , cmais OS X de sed ne fonctionne pas. Par exemple, sed 1iaest une alternative GNU à sed $'1i\\\na\n'.

Par exemple, printf a|sed -n pajoute une nouvelle ligne dans sed sous OS X mais pas dans GNU sed.

OS X sed ne prend pas en charge les modificateurs ( Iinsensibles à la casse) ou M(multilignes). Les nouvelles versions du support sed de FreeBSD I.

OS X sed ne prend pas en charge -s( --separate), -u( --unbuffered) ou -z( --null-data).

Une option BSD non prise en charge par GNU sed est celle -aqui wajoute à un fichier au lieu de tronquer un fichier.

Exemples de commandes GNU sed qui ne fonctionnent pas avec sed:

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
la source
4
-i -ene fonctionne pas sur OSX. Il interpole -ecomme le suffixe.
Chris Martin
3
@ChrisMartin oui, dans la version OS X, -iil faut toujours un suffixe, même s'il s'agit d'une chaîne vide. -i '' -edevrait donc travailler.
waldyrious
@waldyrious Cela ne fonctionne que sur OSX.
Chris Martin
oui, c'est un caprice de cette version :)
waldyrious
3
La phrase " -i -efonctionne avec les deux." dans votre réponse suggère qu'il existe une solution multi-plateforme. Apparemment il n'y en a pas.
leondepeon
5

Le meilleur moyen que j’ai trouvé d’avoir le même travail de script sous Linux et Mac est la suivante:

sed -i.bak -e 's/foo/bar/' -- "${TARGET}" &&
  rm -- "${TARGET}.bak"
vikrantt
la source
Ou utilisez d' perloù ça -ivient. perl -Tpi -e 's/foo/bar/' -- "$TARGET"
Stéphane Chazelas