Recherche…


Introduction

Pour citer la demande de création de sujet de @ SnoringFrog:

«L'un des plus gros problèmes rencontrés avec sed est celui des scripts qui échouent (ou réussissent de manière inattendue) car ils ont été écrits pour l'un et non pour l'autre.

Remarques

macOS utilise la version BSD de sed [1] , qui diffère à plusieurs égards de la version GNU sed fournie avec les distributions Linux .

Leur dénominateur commun est la fonctionnalité décrétée par POSIX : voir la spécification POSIX sed .

L' approche la plus portable consiste à utiliser uniquement les fonctionnalités POSIX , qui limitent toutefois les fonctionnalités :

  • Notamment, POSIX spécifie que le soutien pour les expressions régulières de base, qui ont de nombreuses limites (par exemple, pas de support pour | (alternance) du tout, pas de soutien direct pour les + et ? ) Et des exigences différentes qui s'échappent.

    • Caveat: GNU sed (sans -r ), pris en charge par \| , \+ et \? , qui n'est PAS compatible POSIX; utiliser --posix pour désactiver (voir ci-dessous).
  • Pour utiliser uniquement les fonctionnalités POSIX :

    • (les deux versions): utilisez uniquement les options -n et -e (notamment, n'utilisez pas -E ou -r pour activer la prise en charge des expressions régulières étendues )

    • GNU sed : possibilité d' ajouter --posix pour assurer la fonctionnalité POSIX uniquement (vous ne strictement pas besoin, mais sans elle , vous pourriez finir par utiliser , par inadvertance , dispose de chambres non-POSIX sans se rendre compte, mise en garde: --posix lui - même est non conforme aux spécifications POSIX )

    • L'utilisation des fonctionnalités uniquement POSIX implique des exigences de formatage plus strictes (renonçant à de nombreuses fonctionnalités disponibles dans GNU sed ):

      • Les séquences de caractères de contrôle telles que \n et \t sont généralement pas prises en charge.
      • Les étiquettes et les commandes de ramification (par exemple, b ) doivent être suivies d'un retour à la ligne réelle ou la continuation par l' intermédiaire d' un séparé -e option.
      • Voir ci-dessous pour plus de détails.

Cependant, les deux versions implémentent des extensions au standard POSIX:

  • quelles extensions ils implémentent diffèrent (GNU sed implémente davantage).
  • même ces extensions qu'elles implémentent toutes deux diffèrent partiellement par leur syntaxe .

Si vous avez besoin de supporter les deux plates-formes (discussion des différences):

  • Caractéristiques incompatibles :

    • L'utilisation de l' option -i sans argument (mise à jour sur place sans sauvegarde) est incompatible:

      • BSD sed : DOIT utiliser -i ''
      • GNU sed : DOIT utiliser juste -i (équivalent: -i'' ) - utiliser -i '' ne fonctionne PAS.
    • -i tourne sensiblement la numérotation des lignes fichier par-entrée dans GNU sed et les versions récentes de BSD sed (par exemple, sur FreeBSD 10), mais pas sur Macos de 10,12.
      Notez qu'en l'absence de -i toutes les versions numérotent les lignes de manière cumulative sur les fichiers d'entrée.

    • Si la dernière ligne en entrée ne comporte pas de nouvelle ligne (et est imprimée):

      • BSD sed : ajoute toujours une nouvelle ligne à la sortie, même si la ligne de saisie ne se termine pas par une.
      • GNU sed : conserve le statut trailing-newline , c'est-à-dire qu'il ajoute une nouvelle ligne uniquement si la ligne d'entrée se termine par une.
  • Caractéristiques communes :

    • Si vous limitez vos scripts sed à ce que supporte BSD sed , ils fonctionneront également sous GNU sed , à l'exception notable des fonctionnalités regex étendues spécifiques à la plate-forme avec -E . Evidemment, vous allez également renoncer à des extensions spécifiques à la version GNU. Voir la section suivante.

Directives pour la prise en charge multi-plateformes (OS X / BSD, Linux), guidées par les exigences plus strictes de la version BSD :

Notez que les raccourcis macOS et Linux sont occasionnellement utilisés ci-dessous pour faire référence respectivement aux versions BSD et GNU de sed , car ce sont les versions stock sur chaque plate-forme. Cependant, il est possible d'installer GNU sed sur macOS, par exemple, en utilisant Homebrew avec brew install gnu-sed .

Remarque : Sauf lorsque les indicateurs -r et -E sont utilisés (expressions rationnelles étendues ), les instructions ci-dessous reviennent à écrire des scripts sed conformes à POSIX .

  • Pour la conformité POSIX, vous devez vous limiter aux POSIX (expressions régulières de base ) , qui, malheureusement, sont assez simples, comme leur nom l'indique.
    Avertissement : ne présumez pas que \| , \+ et \? sont supportés: bien que GNU sed supporte (sauf si --posix est utilisé), BSD sed ne le fait pas - ces fonctionnalités ne sont pas compatibles avec POSIX.
    Alors que \+ et \? peut être émulé de manière compatible POSIX:
    \{1,\} pour \+ ,
    \{0,1\} pour \? ,
    \| (alternance) ne peut malheureusement pas.

  • Pour des expressions régulières plus puissantes, utilisez -E (plutôt que -r ) pour prendre en charge les ERE (expressions régulières étendues ) (GNU sed ne documente pas -E , mais il fonctionne comme alias de -r ; version plus récente de BSD sed , comme sur FreeBSD 10, maintenant supporte également -r , mais la version macOS à partir de 10.12 ne le fait pas .
    Avertissement: Même si l' utilisation de -r / -E signifie que votre commande est par définition non conforme aux spécifications POSIX, vous devez toujours vous limiter à ERE (POSIX Les expressions régulières étendues) . Malheureusement, cela signifie que vous ne pourrez pas utiliser plusieurs constructions utiles, notamment:

    • assertions de limites de mots, car elles sont spécifiques à la plate-forme (par exemple, \< sous Linux, [[:<]] sous OS X).
    • références arrière à l' intérieur des expressions régulières (par opposition aux « références arrière » pour les matches de capture-groupe dans la chaîne de remplacement s appels de fonction), car BSD sed ne les supporte pas regexes étendus (mais, curieusement, le fait en ceux de base , où ils sont mandatés POSIX).
  • Séquences d'échappement de caractère de contrôle telles que \n et \t :

    • Dans regexes ( à la fois dans les modèles de sélection de ligne et le premier argument de la s fonction), on suppose que seule \n est reconnue comme une séquence d'échappement (rarement utilisé, étant donné que l'espace de travail est généralement une seule ligne (sans terminer \n ), mais pas à l'intérieur d'une classe de caractères , de sorte que, par exemple, [^\n] ne fonctionne pas (si votre entrée ne contient aucun caractère de contrôle autre que \t , vous pouvez émuler [^\n] avec [[:print:][:blank:]] ; sinon, les caractères de contrôle splice. in en tant que littéraux [2] ) - incluent généralement les caractères de contrôle en tant que littéraux , soit par des chaînes citées ANSI ( $'\t' ) dans les shells qui le supportent ( bash, ksh, zsh ), ou via des substitutions de commandes en utilisant printf (par exemple, "$(printf '\t')" ) .

      • Linux uniquement:
        sed 's/\t/-/' <<<$'a\tb' # -> 'a-b'
      • OSX et Linux:
        sed 's/'$'\t''/-/' <<<$'a\tb' # ANSI C-quoted string
        sed 's/'"$(printf '\t')"'/-/' <<<$'a\tb' # command subst. with printf
    • Dans les chaînes de remplacement utilisées avec la commande s , supposons qu'aucune séquence d'échappement de caractère de contrôle n'est prise en charge , donc, à nouveau, incluez des caractères de contrôle. comme littéraux , comme ci-dessus.

      • Linux uniquement:
        sed 's/-/\t/' <<<$'ab' # -> 'a<tab>b'
      • MacOS et Linux:
        sed 's/-/'$'\t''/' <<<'a-b'
        sed 's/-/'"$(printf '\t')"'/' <<<'a-b'
    • Idem pour les arguments textuels aux fonctions i et a : n'utilisez pas de séquences de caractères de contrôle - voir ci-dessous.

  • Les étiquettes et les branchements : les étiquettes ainsi que l' argument label-name des fonctions b et t doivent être suivis d'une ligne littérale ou d'un $'\n' . Vous pouvez également utiliser plusieurs options -e et terminer chacune après le nom de l'étiquette.

    • Linux uniquement:
      sed -n '/a/ bLBL; d; :LBL p' <<<$'a\nb' # -> 'a'
    • MacOS et Linux:
      • SOIT (nouvelles lignes actuelles):
        sed -n '/a/ bLBL d; :LBL p' <<<$'a\nb'
      • OU ( $\n instances épissées):
        sed -n '/a/ bLBL'$'\n''d; :LBL'$'\n''p' <<<$'a\nb'
      • OU (options -e multiples):
        sed -n -e '/a/ bLBL' -e 'd; :LBL' -e 'p' <<<$'a\nb'
  • Fonctions i et a pour insérer / ajouter du texte: suivre le nom de la fonction par \ , soit suivie par une nouvelle ligne littérale ou un épissé en $'\n' avant de préciser l'argument texte.

    • Linux uniquement:
      sed '1 i new first line' <<<$'a\nb' # -> 'new first line<nl>a<nl>b'
    • OSX et Linux:
      sed -e '1 i\'$'\n''new first line' <<<$'a\nb'
    • Remarque:
      • Sans -e , l'argument de texte n'est inexplicablement pas terminé par une nouvelle ligne en sortie sur macOS (bug?).
      • N'utilisez pas les caractères d'échappement tels que \n et \t dans l'argument texte, car ils ne sont pris en charge que sous Linux.
      • Par conséquent, si l'argument de texte comporte des nouvelles lignes intérieures, \ -escape les.
      • Si vous souhaitez placer des commandes supplémentaires après l'argument textuel, vous devez le terminer par une nouvelle ligne (non échapée) (littérale ou intégrée) ou continuer avec une option -e distincte (il s'agit d'une exigence générale qui s'applique à toutes les versions). .
  • À l'intérieur des listes de fonctions (appels de fonctions multiples inclus dans {...} ), veillez également à terminer la dernière fonction, avant la fermeture } , avec ; .

    • Linux uniquement:
      • sed -n '1 {p;q}' <<<$'a\nb' # -> 'a'
    • MacOS et Linux:
      • sed -n '1 {p;q;}' <<<$'a\nb'

Les caractéristiques spécifiques à GNU sed sont absentes de BSD sed :

Les fonctionnalités GNU qui vous manqueront si vous devez supporter les deux plates-formes:

  • Diverses options de correspondance et de substitution des expressions rationnelles (à la fois dans les modèles pour la sélection des lignes et dans le premier argument de la fonction s ):

    • L'option I pour l'appariement de regex sensible à la casse (incroyablement, BSD sed ne le supporte pas du tout).
    • L'option M pour la correspondance de plusieurs lignes (où ^ / $ correspond au début / à la fin de chaque ligne )
    • Pour plus d'options spécifiques à la fonction s , voir https://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command
  • Séquences d'échappement

  • Les extensions d'adresse , telles que first~step pour faire correspondre chaque étape, addr, +N pour correspondre à N lignes après addr , ... - voir http://www.gnu.org/software/sed/manual/sed. html # Adresses


[1] La version macOS sed est antérieure à la version des autres systèmes de type BSD tels que FreeBSD et PC-BSD. Malheureusement, cela signifie que vous ne pouvez pas supposer que les fonctionnalités fonctionnant sous FreeBSD, par exemple, fonctionneront de la même manière sous macOS.

[2] La chaîne $'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177' caractères ANSI C-quoted $'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177' contient tous les caractères de contrôle ASCII sauf \n (et NUL), vous pouvez donc l'utiliser en combinaison avec [:print:] pour une émulation assez robuste de [^\n] :
'[[:print:]'$'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177'']

Remplacer toutes les nouvelles lignes par des onglets

Note: Pour des raisons de brièveté, les commandes utilisent les chaînes here-strings ( <<< ) et les guillemets ANSI ( $'...' ) . Ces deux fonctionnalités de shell fonctionnent sous bash , ksh et zsh .

# GNU Sed
$ sed ':a;$!{N;ba}; s/\n/\t/g' <<<$'line_1\nline_2\nline_3'
line_1 line_2 line_3

# BSD Sed equivalent (multi-line form)
sed <<<$'line_1\nline_2\nline_3' '
:a
$!{N;ba
}; s/\n/'$'\t''/g'

# BSD Sed equivalent (single-line form, via separate -e options)
sed -e ':a' -e '$!{N;ba' -e '}; s/\n/'$'\t''/g' <<<$'line 1\nline 2\nline 3'

Notes BSD Sed:

  • Notez la nécessité de terminer les étiquettes ( :a ) et les commandes de branchement ( ba ) avec des nouvelles lignes ou avec des options -e distinctes.

  • Comme les séquences d'échappement de caractère de contrôle telles que \t ne sont pas prises en charge dans la chaîne de remplacement, un littéral de tabulation ANSI C-cité est épissé dans la chaîne de remplacement.
    (Dans la partie regex , BSD Sed ne reconnaît que \n comme séquence d'échappement).

Ajouter du texte littéral à une ligne avec la fonction 'a'

Note: Pour des raisons de brièveté, les commandes utilisent les chaînes here-strings ( <<< ) et les guillemets ANSI ( $'...' ) . Ces deux fonctionnalités de shell fonctionnent sous bash , ksh et zsh .

 # GNU Sed
 $ sed '1 a appended text' <<<'line 1'
 line 1
 appended text

 # BSD Sed (multi-line form)
 sed '1 a\
 appended text' <<<'line 1'

 # BSD Sed (single-line form via a Bash/Ksh/Zsh ANSI C-quoted string)
 sed $'1 a\\\nappended text' <<<'line 1'

Notez que BSD Seed nécessite un \ suivi d'une nouvelle ligne pour transmettre le texte à ajouter.
Il en va de même pour les fonctions i (insert) et c (delete et insert) associées.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow