Quelle est la différence entre deux commandes sed ci-dessous?

Informations sur l’environnement dans lequel je travaille:

$ uname -a AIX prd231 1 6 00C6B1F74C00 $ oslevel -s 6100-03-10-1119 

Bloc de code a

 ( grep schdCycCleanup $DCCS_LOG_FILE | sed 's/[~]/ \ /g' | grep 'Move(s) Exist for cycle' | sed 's/[^0-9]*//g' ) > cycleA.txt 

Bloc de code B

 ( grep schdCycCleanup $DCCS_LOG_FILE | sed 's/[~]/ \n/g' | grep 'Move(s) Exist for cycle' | sed 's/[^0-9]*//g' ) > cycleB.txt 

J’ai deux blocs de code (illustrés ci-dessus) qui utilisent sed pour réduire l’entrée à 6 chiffres, mais une commande se comporte différemment de ce à quoi je m’attendais.

Exemple d’entrée pour les deux blocs de code

 Mar 25 14:06:16 prd231 ajbtux[33423660]: 20160325140616:~schd_cem_svr:1:0:SCHD-MSG-MOVEEXISTCYCLE:200705008:AUDIT:~schdCycCleanup - /apps/dccs/ajbtux/source/SCHD/schd_cycle_cleanup.c - line 341~ SCHD_CYCLE_CLEANUP - Move(s) Exist for cycle 389210~ 

J’obtiens la sortie suivante lorsque l’échantillon ci-dessus passe par les deux blocs de code.

contenu cycleA.txt

 389210 

contenu de cycleB.txt

 25140616231334236602016032514061610200705008341389210 

Je comprends que ma dernière commande sed (sed ‘s / [^ 0-9] * // g’) supprime tous les caractères autres que les nombres, donc je les ai omis des codes de bloc et placé la sortie dans deux fichiers supplémentaires. Je reçois la sortie suivante.

contenu cycleA1.txt

  SCHD_CYCLE_CLEANUP - Move(s) Exist for cycle 389210 

contenu de cycleB1.txt

 Mar 25 15:27:58 prd231 ajbtux[33423660]: 20160325152758: nschd_cem_svr:1:0:SCHD-MSG-MOVEEXISTCYCLE:200705008:AUDIT: nschdCycCleanup - /apps/dccs/ajbtux/source/SCHD/schd_cycle_cleanup.c - line 341 n SCHD_CYCLE_CLEANUP - Move(s) Exist for cycle 389210 n 

Je peux voir que le premier bloc de code supprime tout ce qui a autre chose (SCHD_CYCLE_CLEANUP – Move (s) Existe pour le cycle 389210) et utilise le tilde mais le second bloc de code remplace simplement les tildes par le caractère n. Je peux également voir qu’il est nécessaire dans le premier bloc de code pour un saut de ligne après cela (sed ‘s / [~] /) et c’est pourquoi je pense que \ n simulerait un saut de ligne mais ce n’est pas le cas. Je pense que mes différents résultats sont dus à la manière dont les expressions régulières sont utilisées. J’ai essayé de chercher des expressions régulières et de chercher à leur sujet sur stackoverflow mais je n’ai pas obtenu ce que je cherchais. Quelqu’un pourrait-il expliquer comment je peux obtenir le même résultat du bloc de code B que le bloc de code A sans qu’une partie de mon code soit sur une deuxième ligne?

Merci d’avance

La réponse utile d’Etan Reisner explique le problème et propose une solution à une seule ligne basée sur une chaîne de caractères ANSI C-quoted ( $'...' ), ce qui est approprié, étant donné que vous avez initialement tagué votre question.
( La réponse utile d’Ed Morton vous montre comment contourner votre problème avec une approche différente, à la fois plus simple et plus efficace.)

Cependant, il semble que votre shell soit en réalité quelque chose de différent – sans doute ksh88 , une ancienne version du shell Korn qui est le sh par défaut sous AIX 6.1 – dans lequel ces chaînes ne sont pas supscopes [1] ksh93 , et sont également supportés non seulement dans bash , mais aussi dans zsh ).

Ainsi, vous avez les options suivantes:

  • Avec votre shell actuel, vous devez vous en tenir à une solution à deux lignes qui contient une nouvelle ligne ( \ -escapée), comme dans votre bloc de code A.

    • Notez que $(printf '\n') pour créer une nouvelle ligne ne fonctionne pas , car les substitutions de commandes suppriment invariablement toutes les nouvelles lignes, ce qui entraîne la chaîne vide dans ce cas.
  • Utilisez un shell plus moderne qui prend en charge les chaînes ANSI citées et utilisez la réponse d’Etan. http://www.ibm.com/support/knowledgecenter/ssw_aix_61/com.ibm.aix.cmds3/ksh.htm me dit que ksh93 est disponible en tant que shell alternatif sous AIX 6.1, sous la forme /usr/bin/ksh93 .

  • Si possible: installez GNU sed , qui comprend nativement les séquences d’échappement telles que \n dans les chaînes de remplacement.


[1] Quant à ce qui se passe réellement lorsque vous essayez echo 'foo~bar~baz' | sed $'s/[~]/\\\n/g' echo 'foo~bar~baz' | sed $'s/[~]/\\\n/g' dans un shell de type POSIX qui ne supporte pas $'...' : le $ rest tel quel, car ce qui suit n’est pas un nom de variable valide , et sed finit par voir littéralement $s/[~]/\\\n/g , où $ est interprété comme une adresse de contexte s’appliquant à la dernière ligne d’entrée – ce qui ne fait pas de différence ici, car il n’y a que 1 ligne. \\ est interprété comme plaine \ et \n comme plaine n , remplaçant efficacement les ~ instances par des séquences littérales \n .

Ceci est un exemple du problème XY ( http://xyproblem.info/ ). Vous demandez de l’aide pour mettre en œuvre quelque chose qui est la mauvaise solution à votre problème. Pourquoi changez-vous ~ s en nouvelles lignes, etc. lorsque tout ce dont vous avez besoin compte tenu de votre exemple d’entrée et de résultats attendus est:

 $ sed -n 's/.*schdCycCleanup.* \([0-9]*\).*/\1/p' file 389210 

ou:

 $ awk -F'[ ~]' '/schdCycCleanup/{print $(NF-1)}' file 389210 

Si ce n’est pas tout ce dont vous avez besoin, veuillez modifier votre question afin de clarifier vos exigences pour ce que vous essayez de faire (par opposition à COMMENT vous essayez de le faire) car votre approche actuelle est tout simplement fausse.

GNU sed gère \n le remplacement comme vous le souhaitez.

OS X (et probablement BSD) sed ne le fait pas. Il le traite comme un caractère échappé normal et ne le comprend que par n . (Bien que je ne le vois pas dans le manuel nulle part)

Vous pouvez utiliser $'' guillemets $'' pour utiliser \n comme une nouvelle ligne si vous le souhaitez.

 echo 'foo~bar~baz' | sed $'s/[~]/\\\n/g'