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
pmaipmui
la source

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.

heemayl
la source
11

Une solution avec cut:

cut -d ' ' -f1-4 -f6- FILE
fd0
la source
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
glenn jackman
la source
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
cuonglm
la source
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).

Scott
la source
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
NeronLeVelu
la source
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
Steve
la source
1

Une autre possibilité, en supposant une coupure GNU:

cut -d' ' -f5 --complement file.txt
Traumatisme numérique
la source
-1

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

perl -nE '/^((\w+ +){4})\w+ *(.*)/; say $1.$3' file
Medlock Perlman
la source