web-dev-qa-db-fra.com

Comment puis-je éditer une plage de texte entre 2 symboles? awk, sed, regex

En utilisant le symbole "*" ((il n’est pas nécessaire que ce soit celui-ci, aucun caractère spécial ne le fera pour indiquer)), comment puis-je modifier le texte à partir de ceci:

*berry
straw
rasp
blue
boysen
*
blahblah
blahblah
blahblah
*berry
straw
blue
*
blah
*table
vege
pingpong
*

Pour ça:

strawberry
raspberry
blueberry
boysenberry
blahblah
blahblah
blahblah
strawberry
blueberry
blah
vegetable
pingpongtable

Chaque caractère après le premier astérisque correspondant sera placé sur chaque ligne jusqu'à ce que le deuxième astérisque soit trouvé.

Des pistes sur comment je peux m'y prendre? (sed ou awk serait préféré, mais si vous pouvez penser à une autre façon, s'il vous plaît envoyez-moi votre code!)

Je sais comment supprimer toutes les lignes contenant un astérisque, c'est juste la partie de placement de personnage à laquelle je ne peux pas penser

6
TuxForLife

Ce code awk pourrait suffire:

awk -F'*' 'NF == 2 {label = $2; next} {$0 = $0 label} 1'

Pour le décomposer:

  • Utilisez * comme séparateur de champ. De cette façon, nous pouvons simplement examiner le nombre de champs (NF) pour déterminer si le début ou la fin d'un bloc est atteint.
  • Lorsqu'il y a deux champs, nous sauvegardons le deuxième champ dans label et continuons à la ligne suivante.
  • A partir de là, nous ajoutons cette label à la ligne en cours, puis imprimons. Si l'étiquette est vide, nous sommes en dehors d'un bloc et il n'y a aucun effet. Sinon, nous obtenons la sortie requise.
12
muru

Dans sed, vous pouvez copier la ligne "spéciale" dans l'espace réservé avant de la supprimer.

sed -e '/^\*/{h;d;}'

puis ajoutez l'espace de maintien à chaque espace de motif suivant, en remplaçant le caractère de nouvelle ligne et de marqueur résultant

    -e '{G;s/\n\*//;}'

Le tester avec vos données,

$ sed -e '/^\*/{h;d;}' -e '{G;s/\n\*//;}' file
strawberry
raspberry
blueberry
boysenberry
blahblah
blahblah
blahblah
strawberry
blueberry
blah
vegetable
pingpongtable

Note: cela ne s'arrête pas quand il rencontre le deuxième astérisque; il fait exactement la même chose, mais ajoute * suivi de rien - jusqu'à ce qu'il corresponde au prochain *sometext.

8
steeldriver

Voici un moyen Perl:

_$ Perl -lne '/^\*(.*)/ || print "$_$1"' file
strawberry
raspberry
blueberry
boysenberry
blahblah
blahblah
blahblah
strawberry
blueberry
blah
vegetable
pingpongtable
_

Explication

Le _-n_ amènera Perl à lire chaque ligne du fichier d'entrée, en l'enregistrant dans la variable spéciale _$__, le _-l_ le fera: i) éliminer les nouvelles lignes (_\n_) de chaque ligne et ii) ajouter une nouvelle ligne à chaque appel de print. _-e_ est le script qui est appliqué à chaque ligne.

  • /^\*(.*)/: associe les lignes commençant par un astérisque et enregistre tout ce qui suit après l'astérisque sous le nom _$1_ (c'est ce que font les parenthèses).

  • _|| print "$_$1"'_: le _||_ est un OR logique. Par conséquent, la print ne sera exécutée que si la ligne en cours ne commence pas par un astérisque. Si c'est le cas, nous imprimons la ligne en cours (_$__) ainsi que tout ce qui est actuellement enregistré sous le nom _$1_ (le motif qui suit l'astérisque).


Comme d'habitude, il y a plusieurs façons de le faire. Une solution stupide et inefficace, mais qui met en évidence les capacités de manipulation de chaînes du shell, est la suivante:

_$ while read line; do 
    [[ $line =~ ^\* ]] && pat="${line#\*}" || printf "%s%s\n" "$line" "$pat"; 
  done < file
strawberry
raspberry
blueberry
boysenberry
blahblah
blahblah
blahblah
strawberry
blueberry
blah
vegetable
pingpongtable
_

Explication

  • _while read line; do ... ; done < file_: il s'agit d'une boucle classique while qui lit chaque ligne du fichier d'entrée file et l'enregistre sous le nom _$line_.
  • _[[ $line =~ ^\* ]] && pat="${line#\*}"_: si la ligne commence par un _*_, supprimez tout ce qui suit (c'est ce que fait le _${line#\*}_, pour plus de détails, voir ici ) et enregistrez-le comme _$pat_. * _|| printf "%s%s\n" "$line" "$pat";_: si la commande précédente a échoué (la ligne ne commence donc pas par un astérisque), imprimez la ligne et la valeur actuelle de _$pat_.

7
terdon

À travers mon Python préféré ...

with open('/path/to/the/file') as f:
    counter = False
    for line in f:
        if line.startswith('*') and not counter:
            m = line.strip().lstrip('*')
            counter = True
        Elif line.startswith('*') and counter:
            counter = False    
        Elif counter:
            if not line.startswith('*'):
                print(line.strip() + m)
        else:
            print(line.strip())  
3
Avinash Raj

Je suis arrivé tard. Voici une autre approche python:

#!/usr/bin/env python2
with open('/path/to/file.txt') as f:
    for lines in f.read().split('*'):
        entries = lines.rstrip().split('\n')
        for i in range(1, len(entries)):
            print entries[i] + entries[0]
3
heemayl