Comment supprimer le 5e mot de chaque ligne d'un fichier?


13

Je souhaite supprimer le 5ème mot de chaque ligne d'un fichier.

Le contenu actuel du fichier:

File is not updated or and will be removed  
System will shut down f within 10 seconds  
Please save your work 55 or copy to other location  
Kindly cooperate with us D  

Production attendue:

File is not updated and will be removed  
System will shut down within 10 seconds  
Please save your work or copy to other location  
Kindly cooperate with us

Réponses:


31

Que diriez-vous cut:

$ cut -d' ' -f1-4,6- file.txt 
File is not updated and will be removed  
System will shut down within 10 seconds  
Please save your work or copy to other location  
Kindly cooperate with us
  • -d' ' définit le délimiteur comme espace

  • -f1-4,6- sélectionne le premier au 4ème champ (mot), en laissant le 5ème puis continuez l'impression du 6ème au reste.


11

Une solution avec cut:

cut -d ' ' -f1-4 -f6- FILE

Multiple -fn'est pas pris en charge dans mon cut(GNU) au moins ..
— heemayl

Pris en charge dans la coupe BSD mais j'aime mieux votre réponse que la mienne.
— fd0

1
Si elle est coupée GNU, vous obtenez le --complementdrapeau pour simplifier les choses: cut --complement -d ' ' -f5. N'oubliez pas de rediriger la sortie vers un nouveau fichier, puis mvsur l'original.
— Toby Speight

6

awk: supprimer le 5ème champ

awk '{for (i=5; i<NF; i++) $i = $(i+1); NF--};1' file

Si vous souhaitez enregistrer le fichier sur place: /programming//q/16529716/7552

Vous pouvez simplement effacer le contenu du 5ème champ, mais cela laisse 2 séparateurs de champ de sortie consécutifs:

awk '{$5 = ""};1' file

la mise en garde ici est que la modification de la valeur de n'importe quel champ dans awk a pour effet secondaire de réécrire le "$ 0" avec un seul séparateur entre chaque champ. doit être pris en compte si vous souhaitez conserver un alignement (sauf si gnu awk a une option pour éviter cela? awk / nawk régulier recalculera 0 $)
— Olivier Dulac

Dans les deux cas, vous reformatez la ligne avec un seul séparateur. S'il y a 2 espaces ou espace + tabulation dans un séparateur, le résultat est un seul espace en place. C'est très bien pour la plupart du texte.
— NeronLeVelu

4

Avec POSIX sed:

sed -e 's/[^[:alnum:]_][[:alnum:]_][[:alnum:]_]*//4' <file

pourquoi limiter la classe à: alnum: et _ et rien d'autre alors :blank:ou :space:?
— NeronLeVelu

@NeronLeVelu: Cela dépend de la façon dont vous définissez ce qui fait un mot.
— cuonglm

@mikeserv; Belle prise! J'ai mis à jour ma réponse.
— cuonglm

À quoi sert le \(groupe de capture \)?
— mikeserv

@mikeserv: ma faute de frappe, je viens d'essayer quelques façons de conserver le délimiteur.
— cuonglm

2

glenn a proposé une solution équivalente à

awk '{$ 5 = ""; print} ' fichier

Comme lui et d’autres l’ont souligné, cette

  1. supprime les espaces blancs de début et de fin de chaque ligne,
  2. compresse chaque chaîne d'espaces (espaces et / ou tabulations) en un seul espace, et
  3. laisse deux espaces entre le quatrième et six mots.

Un hack pour résoudre le troisième problème est

awk '{$ 5 = ""; print} ' fichier | sed 's / / /'

Cela laissera toujours un ou plusieurs espaces ajoutés à la fin de toute ligne contenant cinq mots ou moins. Si vous pouvez identifier un mot qui n'apparaîtra jamais dans l'entrée,

awk '{$ 5 = "licorne"; print} ' fichier | sed 's / * licorne //'

gérera même cela (mais cela laisse toujours les problèmes 1 et 2).


2
 sed 's/^\(\([[:blank:]]*[^[:blank:]]\{1,\}\)\{4\}\)[[:blank:]]*[^[:blank:]]*/\1/' YourFile > Output.txt
  • posix sed basé sur le séparateur espace / tabulation (méta-classe [: vide:]])
  • garder l'espace suivant après le 5ème mot mais en supprimant celui d'avant

Une version plus robuste (sed prend le modèle le plus long possible et le modèle avec *pourrait manquer la séparation ou le mot dans la première version) mais une version un peu plus longue

sed 's/^\([[:blank:]]*\([^[:blank:]]\{1,\}[[:blank:]]\{1,\}\)\{4\}\[^[:blank:]]\{1,\}/\1/' YourFile > Output.txt

1
sed 's/[^[:blank:]]*//5'
— mikeserv

@mikeserv, cela gardera les deux séparateurs environnants, sed 's/[[:blank:]*[^[:blank:]]*//5'c'est mieux. Très bon point. Je soupçonnais sed de prendre chaque caractère comme une entité, mais cela prend le plus grand modèle incassable en tant qu'entité
— NeronLeVelu

sed 's/[[:blank:]][^[:blank:]]*//4'supprimera entièrement le 5ème champ.
— mikeserv

@mikeserv En supposant qu'il n'y a pas d'espace de départ sur la ligne (comme dans l'exemple)
— NeronLeVelu

Dans ce cas, oui, je pense que vous avez raison. Habituellement, une telle chose serait un champ nul et le comportement serait correct. Dans ce cas , vous devriez faire comme @cuonglm fait et vous assurer que vous faites référence à un mot à chaque fois comme sed 's/[[:blank:]][^[:blank:]][^[:blank:]]*//4', ou, w / GNU / BSD / Toybox seds: sed -E 's/[[:blank:]][^[:blank:]]+//4'.
— mikeserv

1

Perl.

perl -ne 'print $_ =~ /^(\w+ +\w+ +\w+ +\w+ +)\w+ (.*)/,"\n"' file


-1

Utilisation de Perl> 5.10 (et sortie réussie de toutes les lignes: 0)): -

perl -nE '/^((\w+ +){4})\w+ *(.*)/; say $1.$3' file
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.