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.