Comment remplacer une partie d'un fichier texte entre des marqueurs par un autre fichier texte?

26

Disons que j'ai un fichier texte comme celui-ci:

# custom content section
a
b

### BEGIN GENERATED CONTENT
c
d
### END GENERATED CONTENT

Je voudrais remplacer la partie entre les GENERATED CONTENTbalises par le contenu d'un autre fichier.

Quelle est la manière la plus simple de procéder?

smokris
la source

Réponses:

36
lead='^### BEGIN GENERATED CONTENT$'
tail='^### END GENERATED CONTENT$'
sed -e "/$lead/,/$tail/{ /$lead/{p; r insert_file
        }; /$tail/p; d }"  existing_file
Peter.O
la source
Excellent. sedpeut faire bien plus que juste s/.../...!
DevSolar
Hmmm ne fonctionne pas pour moi, dois-je mettre la commande sed sur une seule ligne?
lzap
3
La r insert_filecommande doit être la dernière chose sur sa ligne. Notez que ni les espaces ni les commentaires ne sont autorisés après. Le code a été testé en utilisant GNU sedavec l' --posixoption activée, et il a fonctionné comme prévu, donc il devrait fonctionner avec n'importe quel compatible posix sed .
Peter.O
1
Holy moly, c'est cool! Cela va dans mon dictionnaire sed! Superbement utile et magnifiquement simple. Merci!
DanielSmedegaardBuus
2
Notez qu'une modification sur place nécessite que vous capturiez la sortie de sed (par exemple output=$(sed -e "..." existing_file)), puis effectuez le remplacement dans un deuxième passage (par exemple echo "$output" > existing_file) car essayer de rediriger vers un fichier que vous lisez le fera tronquer avant la lecture du contenu.
Chris Tonkinson
5
newContent=`cat new_file`
perl -0777 -i -pe "s/(### BEGIN GENERATED CONTENT\\n).*(\\n### END GENERATED CONTENT)/\$1$newContent\$2/s" existing_file
smokris
la source
Bon travail. Beaucoup plus simple que le mien. :)
Dr Kitty
4

Avertissement: ce n'est certainement pas la façon la plus simple de le faire. (EDIT: bash fonctionne; grep POSIX est très bien aussi)

Si le texte principal se trouve dans le fichier "main" et que le contenu généré est dans le fichier "gen", vous pouvez procéder comme suit:

#!/bin/bash
BEGIN_GEN=$(cat main | grep -n '### BEGIN GENERATED CONTENT' | sed 's/\(.*\):.*/\1/g')
END_GEN=$(cat main | grep -n '### END GENERATED CONTENT' | sed 's/\(.*\):.*/\1/g')
cat <(head -n $(expr $BEGIN_GEN - 1) main) gen <(tail -n +$(expr $END_GEN + 1) main) >temp
mv temp main
Dr Kitty
la source
Est-ce que ça marche? Je pense que votre dernière ligne s'ouvrira mainpour l'écriture, l'effaçant, avant qu'elle ne soit lue par le chat.
chepner
@chepner Crap, vous avez raison. Le reste fonctionne, cependant. Je le réparerai.
Dr Kitty
3
ed -s FILE1 <<EOF
/### BEGIN GENERATED/+,/### END GENERATED/-d
/### BEGIN GENERATED/ r FILE2
w
q
EOF
Jetchisel
la source
Utilisation d'un hérédoc et de l'éditeur de ligne ed. La première ligne à l'intérieur de l'hérédoc doit supprimer 'd' la ligne après '+' la '### BEGIN gENERATED ...' et la ligne avant '-' la '### END GENERATED ...' la deuxième ligne consiste à insérer FILE2 après la ligne ### END GENERATED ... '
Jetchisel
désolé ce que je voulais dire était d'insérer FILE2 après la ligne '### BEGIN GENERATED ..'
Jetchisel
Allez-y doucement, c'est après tout ma première fois :-). Aussi, j'aurais peut-être utilisé le même mot, mais l'autre solution n'utilise pas un heredocs mais un printf et un pipe. Toutes
mes
Merci, très lisible! Btw - au lieu de r FILE2vous pouvez dire r !commandde lire à partir d'un script différent.
Kos