mon fichier texte ressemble à ceci:
Liquid penetration 95% mass (m) = 0.000205348
Liquid penetration 95% mass (m) = 0.000265725
Liquid penetration 95% mass (m) = 0.000322823
Liquid penetration 95% mass (m) = 0.000376445
Liquid penetration 95% mass (m) = 0.000425341
maintenant, je veux supprimer Liquid penetration 95% mass (m)
de mes lignes pour obtenir les valeurs uniquement. Comment devrais-je le faire?
S'il n'y a qu'un seul signe =
, vous pouvez tout supprimer avant et y compris =
comme ceci:
$ sed -r 's/.* = (.*)/\1/' file
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341
Si vous souhaitez modifier le fichier d'origine, utilisez l'option -i
après le test:
sed -ri 's/.* = (.*)/\1/' file
-r
utilise ERE, nous n'avons donc pas à échapper à (
et à )
s/old/new
remplace old
par new
name__.*
n'importe quel nombre de caractères(things)
save things
to backreference ultérieurement avec \1
, \2
, etc.C'est un travail pour awk
; en supposant que les valeurs apparaissent dans le dernier champ uniquement (selon votre exemple):
awk '{print $NF}' file.txt
NF
est une variable awk
, étend au nombre de champs dans un enregistrement (ligne), donc $NF
(notez le $
devant) contient la valeur du dernier champ.Exemple:
% cat temp.txt
Liquid penetration 95% mass (m) = 0.000205348
Liquid penetration 95% mass (m) = 0.000265725
Liquid penetration 95% mass (m) = 0.000322823
Liquid penetration 95% mass (m) = 0.000376445
Liquid penetration 95% mass (m) = 0.000425341
% awk '{print $NF}' temp.txt
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341
Avec grep
et le -P
pour avoir PCRE
(Interpréter le motif comme un P erl - C compatible R égal à E xpression) et le -o
pour imprimer le motif correspondant uniquement. La notification \K
ignorera la partie correspondante avant elle-même.
$ grep -oP '.*= \K.*' infile
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341
Ou vous pouvez utiliser la commande cut
.
cut -d= -f2 infile
J'ai décidé de comparer les différentes solutions énumérées ici. À cette fin, j'ai créé un fichier volumineux, basé sur le contenu fourni par l'OP:
J'ai créé un fichier simple, nommé input.file
:
$ cat input.file
Liquid penetration 95% mass (m) = 0.000205348
Liquid penetration 95% mass (m) = 0.000265725
Liquid penetration 95% mass (m) = 0.000322823
Liquid penetration 95% mass (m) = 0.000376445
Liquid penetration 95% mass (m) = 0.000425341
Puis j'ai exécuté cette boucle:
for i in {1..100}; do cat input.file | tee -a input.file; done
La fenêtre du terminal était bloquée. J'ai exécuté killall tee
à partir d'un autre terminal. Ensuite, j'ai examiné le contenu du fichier à l'aide des commandes: less input.file
et cat input.file
. Cela avait l'air bien, sauf la dernière ligne. J'ai donc supprimé la dernière ligne et créé une copie de sauvegarde: cp input.file{,.copy}
(à cause des commandes qui utilisent l'option inplace ).
Le nombre final de lignes dans le fichier input.file
est 2 192 473 . J'ai eu ce numéro avec la commande wc
:
$ cat input.file | wc -l
2192473
Voici le résultat de la comparaison:
$ time grep -o '[^ [: espace:]]\+ $' input.file> output.file réel 0m58.539s utilisateur 0m58.416s Sys 0m0.108s
$ time sed -ri '/.* = (. *)/\ 1 /' input.file réel 0m26.936s utilisateur 0m22. 836s Sys 0m4.092s
Alternativement, si nous redirigeons la sortie vers un nouveau fichier, la commande est plus rapide:
$ time sed -r 's /.* = (. *)/\ 1 /' input.file> output.file Réel 0m19.734s utilisateur 0m19,672s sys 0m0.056s
gawk '{gsub(".*= ", "");print}'
$ time gawk '{gsub (". * =",) "; print}' input.file> output.file réel 0m5.644s utilisateur 0m5,568s sys 0m0.072s
$ time rev input.file | cut -d '' -f1 | rev> fichier.sortie réel 0m3.703s utilisateur 0m2.108s sys 0m4.916s
$ time grep -oP '. * =\K. *' fichier.entrée> fichier.sortie réel 0m3.328s utilisateur 0m3.252s sys 0m0.072s
sed 's/.*= //'
(respectivement l'option -i
rend la commande plus lente)
$ time sed '/.*= //' input.file> output.file Réel 0m3.310s Utilisateur 0m3.212s sys 0m0.092s
Perl -pe 's/.*= //'
(l'option -i
ne produit pas une grande différence de productivité ici)
$ time Perl -i.bak -pe 's /.*= //' input.file real 0m3.187s utilisateur 0m3.128s sys 0m0.056s
$ time Perl -pe '/.*= //' input.file> output.file réel 0m3.138s utilisateur 0m3.036s sys 0m0.100s
$ time awk '{print $ NF}' input.file> output.file real 0m1.251s utilisateur 0m1.164s sys 0m0.084s
$ time cut -c 35- fichier.entrée> fichier.sortie réel 0m0.352s utilisateur 0m0.284s sys 0m0. 064s
$ time coupe -d = -f2 input.file> output.file réel 0m0.328s utilisateur 0m0.260s sys 0m0.064s
Comme le préfixe de ligne a toujours la même longueur (34 caractères), vous pouvez utiliser cut
name__:
cut -c 35- < input.txt > output.txt
Inversez le contenu du fichier avec rev
, dirigez la sortie vers cut
avec un espace comme délimiteur et 1 comme champ cible, puis inversez-le à nouveau pour obtenir le numéro d'origine:
$ rev your_file | cut -d' ' -f1 | rev
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341
C’est simple, court et facile à écrire, à comprendre et à vérifier, et j’aime bien, personnellement:
grep -oE '\S+$' file
grep
dans Ubunt , lorsqu'il est appelé avec -E
ou -P
, prend le raccourci\s
pour signifier un caractère d'espacement (en pratique généralement un espace ou une tabulation) et \S
signifie tout ce qui n'en est pas un. En utilisant le quantificateur +
et l'ancre de fin de ligne $
, , le modèle \S+$
correspond à un ou plusieurs éléments non vides à la fin d'une ligne . Vous pouvez utiliser -P
au lieu de -E
; la signification dans ce cas est la même, mais n moteur d'expressions régulières différent est utilisé. Par conséquent, peut avoir des caractéristiques de performance différentes .
Cela équivaut à la solution commentée d'Avinash Raj (avec une syntaxe plus simple et plus compacte):
grep -o '[^[:space:]]\+$' file
Ces approches ne fonctionneront pas s'il peut y avoir des espaces finaux après le nombre. Ils peuvent être modifiés comme ils le font, mais je ne vois aucune raison de les aborder ici. Bien qu'il soit parfois instructif de généraliser une solution afin de travailler dans plusieurs cas, il n'est pas pratique de le faire aussi souvent que les gens ont tendance à l'assumer, car on n'a généralement aucun moyen de savoir dans lequel de nombreux types différents sont incompatibles. façons le problème pourrait éventuellement devoir être généralisé.
La performance est parfois une considération importante. Cette question ne stipule pas que l'entrée est très importante et il est probable que chaque méthode publiée ici est suffisamment rapide. Toutefois, si la vitesse est souhaitée, voici un petit repère sur un fichier d'entrée de dix millions de lignes:
$ Perl -e 'print((<>) x 2000000)' file > bigfile
$ du -sh bigfile
439M bigfile
$ wc -l bigfile
10000000 bigfile
$ TIMEFORMAT=%R
$ time grep -o '[^[:space:]]\+$' bigfile > bigfile.out
819.565
$ time grep -oE '\S+$' bigfile > bigfile.out
816.910
$ time grep -oP '\S+$' bigfile > bigfile.out
67.465
$ time cut -d= -f2 bigfile > bigfile.out
3.902
$ time grep -o '[^[:space:]]\+$' bigfile > bigfile.out
815.183
$ time grep -oE '\S+$' bigfile > bigfile.out
824.546
$ time grep -oP '\S+$' bigfile > bigfile.out
68.692
$ time cut -d= -f2 bigfile > bigfile.out
4.135
Je l'ai exécuté deux fois au cas où l'ordre importait (comme c'est parfois le cas pour les tâches nécessitant beaucoup d'E/S) et parce que je n'avais pas de machine disponible qui ne faisait pas autre chose en arrière-plan qui pourrait fausser les résultats. Je conclus de ces résultats les conclusions suivantes, du moins provisoirement et pour les fichiers d'entrée de la taille que j'ai utilisée:
Hou la la! Passer -P
(à utiliser PCRE ) plutôt que -G
(valeur par défaut lorsque aucun dialecte n'est spécifié) ou -E
a rendu grep
plus rapide d'un ordre de grandeur supérieur. Donc, pour les gros fichiers, il peut être préférable d’utiliser cette commande plutôt que celle présentée ci-dessus:
grep -oP '\S+$' file
WOW !! La méthode cut
dans la réponse de αғsнιη , cut -d= -f2 file
, est plus rapide que la version la plus rapide de mon chemin! C'était également le gagnant de référence de pa408 , qui couvrait plus de méthodes que cela, mais avec une entrée plus petite - et c'est pourquoi je l'ai choisie, parmi toutes les autres méthodes, à inclure dans mon test. Si les performances sont importantes ou si les fichiers sont énormes, je pense que la méthode cut
de αғsнιη devrait être utilisée.
Cela sert également à rappeler que le simple cut
et paste
utilitaires ne doit pas être oublié, et devrait peut-être être préféré le cas échéant, même s'il existe des outils plus sophistiqués comme grep
qui sont souvent proposés en tant que solutions de première ligne (et auxquels je suis personnellement plus habitué en utilisant).
Perl
- s Remplacez le modèle /.*= /
par une chaîne vide //
:
Perl -pe 's/.*= //' input.file > output.file
Perl -i.bak -pe 's/.*= //' input.file
De Perl --help
:
-e program one line of program (several -e's allowed, omit programfile)
-p assume loop like -n but print line also, like sed
-i[extension] edit <> files in place (makes backup if extension supplied)
sed
- remplace le motif par une chaîne vide:
sed 's/.*= //' input.file > output.file
ou (mais plus lent que ce qui précède) :
sed -i.bak 's/.*= //' input.file
gawk
- remplacez le modèle ".*= "
par une chaîne vide ""
:
gawk '{gsub(".*= ", "");print}' input.file > output.file
De man gawk
:
gsub(r, s [, t]) For each substring matching the regular expression r in the string t,
substitute the string s, and return the number of substitutions.
If t is not supplied, use $0...