2
votes

Comment échanger uniquement des valeurs numériques dans chaque ligne

Je n'ai besoin d'échanger que les valeurs numériques dans chaque ligne après la chaîne spécifique "PIC" en utilisant sed. Par exemple:

bonjour PIC A (12), et ce PIC B (11)

Le résultat souhaité est:

bonjour PIC B (11), et ce PIC A (12)

Les caractères "B" et "A" peuvent différer sur d'autres lignes, mais la chaîne PIC est toujours présente.

J'essaye d'utiliser la commande sed:

echo "bonjour PIC A (12), et ce PIC B (11)" | sed '/ PIC X (12) / s / PIC X (12) / PIC X (11) / g'

mais ne semble pas fonctionner correctement.

Toutes les réponses sont appréciées.


5 commentaires

12 est-il une valeur fixe? Sinon, essayez sed -E 's / (PIC) ([AZ] \ ([0-9] + \)) (. * PIC) ([AZ] \ ([0-9] + \) ) / \ 1 \ 4 \ 3 \ 2 / '


génial! Ça fonctionne! Donc, dans le fichier, il y a beaucoup de lignes et de longueur différente mais il y a toujours des valeurs PIC A (), donc votre code semble tout changer. ! Merci @ WiktorStribiżew !!!


Puis-je savoir où vous avez appris en utilisant la commande sed? Je suis confronté à de nombreuses situations où j'ai besoin d'utiliser cet outil. Merci beaucoup @ WiktorStribiżew


J'utilise Linux depuis presque deux ans maintenant, et presque toutes mes connaissances sur sed proviennent de SO et de sites connexes. Suivez le tag, essayez de répondre aux questions, même si vous ne les postez pas, vous apprendrez beaucoup. Là où sed n'est pas suffisant ou trop encombrant, je passe en Perl. awk s'est avéré une alternative intéressante lorsque les chaînes peuvent être traitées comme des chaînes délimitées par des séparateurs.


@Sunny, fwiw, je viens d'écrire un tutoriel et une référence sed ici . Vos commentaires sont les bienvenus!


3 Réponses :


2
votes

Vous pouvez utiliser la commande substitute directement car elle ne changera que les lignes où la correspondance est trouvée.

Utilisez cette POSIX ERE

sed 's/\(PIC \)\([A-Z]([0-9]*)\)\(.*PIC \)\([A-Z]([0-9]*)\)/\1\4\3\2/'

Ou, POSIX BRE

sed -E 's/(PIC )([A-Z]\([0-9]+\))(.*PIC )([A-Z]\([0-9]+\))/\1\4\3\2/'

Les deux versions diffèrent par les parenthèses d'échappement: dans POSIX BRE, \ (... \) désigne la capture groupes et ( et ) correspondent aux parenthèses littérales, tandis que dans POSIX ERE, c'est l'inverse.

Détails du modèle POSIX ERE:

  • (PIC) - Groupe 1: PIC et espace
  • ([AZ] \ ([0-9] + \)) - Groupe 2: toute lettre ASCII majuscule, (, 1+ chiffres, )
  • (. * PIC) - Groupe 3: 0 ou plusieurs caractères, PIC , espace
  • ([AZ] \ ([0-9] + \)) - Groupe 4: une lettre majuscule, (, 1+ chiffres, ) .


0 commentaires

1
votes

si données dans le fichier 'd', essayé sur gnu sed

sed -E 's/(hello PIC )(\w+)(\S+, and this PIC )(\w+)/\1\4\3\2/' d


3 commentaires

Jamais travaillé avec des fichiers .d, mais je suis sûr que je vais l'utiliser à l'avenir. Merci pour votre réponse!


d est juste (certes cryptiquement!) le nom du fichier d'entrée, ce n'est pas une extension ou quelque chose d'intéressant. Il aurait pu être nommé file ou foo ou autre chose - c'est juste un ancien fichier texte.


Oh je comprends! Merci @EdMorton!



1
votes

Avec n'importe quel sed POSIX:

$ sed 's/\(PIC [[:upper:]]([0-9]*)\)\(.*\)\(PIC [[:upper:]]([0-9]*)\)/\3\2\1/' file
hello PIC B(11), and this PIC A(12)

Si vous n'avez pas de sed POSIX (par exemple, ancien sed sous Solaris), définissez LC_ALL = C et modifiez [: supérieur:] à [AZITED.


8 commentaires

Merci pour cela aussi! :)


Hey Ed, j'essayais de décaler trois mots avec la même commande que vous avez postée, mais ça n'aide pas .. J'essayais de décaler: Si par exemple: OCCURS ## TIMES PIC ## (##) et besoin de faire PIC ## (##) OCCURS ## TIMES .. nombres au lieu de hash .. J'essayais de comprendre la séquence lorsque vous appelez les chaînes. J'ai essayé `` sed -E 's / (OCCURS [0-9] +) (TIMES +) (PIC [0-9] ([0-9] ‌ +)) / \ 3 \ 1 \ 2 /' ' »


@Sunny pourquoi n'utilisez-vous pas la réponse que vous avez acceptée ? Dans tous les cas, postez une nouvelle question avec son propre exemple minimal reproductible pour obtenir de l'aide.


@Sunny pose une nouvelle question mais d'abord - que pensez-vous que TIMES + signifie dans une expression rationnelle? De plus, vous semblez avoir des blancs dans votre chaîne (par exemple OCCURS ## TIMES ) mais pas de blancs ni de méta-caractères qui les correspondent dans votre expression régulière (par exemple (OCCURS [0-9] +) (TIMES +) ) donc c'est une des raisons pour lesquelles il ne correspondra jamais à la chaîne.


oui, j'essaie de trouver des questions correspondantes sur le site Web avant de demander, mais je ne l'ai pas encore trouvé. Et oui, je l'ai eu après vous avoir envoyé le code, alors j'ai essayé ce `` sed -E 's / (OCCURS [0-9]) (TIMES) (PIC [0-9] ([0-9])) / \ 3 \ 1 \ 2 / ‌ '``, mais ne fonctionnait pas aussi bien


Comment pourrait cela fonctionner lorsque votre chaîne contient des espaces mais pas votre expression rationnelle? Si vous voulez faire correspondre une chaîne comme xxx yyyy qui a des espaces au milieu, vous devez écrire une expression rationnelle qui tient compte des espaces au milieu, par exemple une variante de x + + y + , pas seulement x + y + sans espace entre les deux.


J'ai eu cet exemple sur le site Web, je ne sais pas comment utiliser vraiment l'expression rationnelle, alors j'ai pensé que cela fonctionnerait.


Le livre que je vous ai recommandé d'apprendre awk, Effective Awk Programming 4th Edition, contient un chapitre qui vous apprend les regexps. L'auteur a également rendu le livre disponible en ligne gratuitement afin que nous puissions tous bénéficier de son référencement, mais tout le monde devrait en acheter un exemplaire car c'est la seule façon dont il est payé pour fournir du gawk et de la documentation. Consultez donc gnu.org/software/gawk/manual/gawk.html #Regexp et achetez le livre !