J'ai une liste de fichiers (fondamentalement, ce sont des packages .deb
). Disons:
abc-de-1.2.3-1.deb
fgh-ij-4.5.6-2.deb
klm-no-7.8.9-3.deb
pqrs-10.11.12-4.deb
...
Comme vous pouvez le constater, certains noms de fichiers portent des chiffres après un -
, tandis que d'autres ont un texte après un -
, puis des chiffres après le prochain -
.
Existe-t-il un moyen de tout supprimer à partir des chiffres, y compris le -
, c.-à-d.,
abc-de
fgh-ij
klm-no
pqrs
...
Je veux éditer la liste, pas renommer les fichiers.
Si vous pouvez utiliser le premier numéro pour identifier ce que vous souhaitez supprimer à chaque fois, vous pouvez utiliser:
$ sed 's/-[0-9].*//' file
abc-de
fgh-ij
klm-no
pqrs
s/old/new/
remplace old
par new
[0-9]
un chiffre.*
un nombre quelconque de caractèresUtilisation de grep
avec des expressions régulières Perl:
$ grep -Po "^[a-z-]*(?=-[0-9])" filename
abc-de
fgh-ij
klm-no
pqrs
$ Perl -lne 's/([[:digit:]].*)//;s/-$//;print' input.txt
abc-de
fgh-ij
klm-no
pqrs
Cela effectue deux substitutions, une pour supprimer tout ce qui commence par un chiffre, et supprime le -
final. Utilisez les options -i
pour éditer le fichier d'origine, comme $ Perl -i -lne 's/([[:digit:]].*)//;s/-$//;print' input.txt
Alternativement, avec une correspondance et un regroupement gourmands sans chiffres:
$ Perl -lne 's/^(\D*)-.*/\1/;print' input.txt
abc-de
fgh-ij
klm-no
pqrs
$ awk -F '-' '{s=$1;for(i=2;i<=NF;i++) if($i~/[0-9].*/){print s;next}else{s=s"-"$i}}' input.txt
abc-de
fgh-ij
klm-no
pqrs
La façon dont cela fonctionne est que nous traitons -
comme un séparateur de champs, puis itérons sur chaque ligne. Nous "mettons en cache" le premier champ et continuons l'itération à l'aide de la boucle for
. À chaque itération, nous vérifions si la colonne ne contient pas un nombre que nous plaçons dans la variable s
. Si la colonne contient un numéro, nous imprimons ce que nous avons sauvegardé et passons à la ligne suivante.
Utilisez > new_file.txt
à la fin pour rediriger la sortie vers un nouveau fichier.
#!/usr/bin/env python
import sys,re
with open(sys.argv[1]) as f:
for line in f:
tokens = re.split("-|\.",line.strip().replace(".deb",""))
words_only = filter(lambda x: not x.isdigit(),tokens)
print("-".join(words_only))
En utilisant re.split()
, nous décomposons chaque ligne en une liste de jetons et ne filtrons que les jetons non numériques.
Alternativement, voici une commande one-liner. Cela ne prend pas de précaution dans le cas où il n'y a pas de chiffre en ligne, utilisez-le uniquement si vous êtes sûr que toutes les lignes contiennent des chiffres.
$ python -c 'import re,sys;f=open(sys.argv[1]);print("\n".join([ l[:re.search(r"\d",l).start()-1] for l in f]))' input.txt
hvd a bien noté dans les commentaires qu'il peut parfois y avoir des entiers dans les noms de paquets, ce qui peut présenter des difficultés pour analyser le fichier d'entrée, alors que les noms de version comportent généralement des points. Dans cet esprit, les commandes peuvent être légèrement modifiées pour contrer cela:
$ Perl -lne 's/\d*\..*//;s/-$//;print' input.txt
$ awk '{gsub(/[0-9]*\..*/,"");print substr($0,0,length($0)-1)};' input.txt
$ python -c 'import re,sys;f=open(sys.argv[1]);print("\n".join([ l[:re.search(r"\d*\.",l).start()-1] for l in f]))' input.txt
À travers awk,
awk -F'-[0-9]' '{print $1}' file
Dans awk, nous pouvons également passer une expression rationnelle comme argument à Field Separator -F
. Donc, cela diviserait chaque ligne de la partie où la regex correspond.
Exemple:
$ echo 'abc-de-1.2.3-1.deb' | awk -F'-[0-9]' '{print $1}'
abc-de
Je vais essayer de deviner, puisque vous avez suggéré que les fichiers sont des paquets DEB, alors, vous vouliez peut-être quelque chose comme:
dpkg-query -f '${Package}\n' -W 'gnome*'
Où, au lieu de gnome*
, vous pouvez substituer n’importe quel motif. Je ne sais pas exactement quelle est la convention exacte pour nommer les archives DEB, mais si ce sont des archives DEB, il est probablement préférable de vous fier à dpkg
pour vous donner le nom du paquet.
Et s’il s’agit de fichiers d’archive DEB (sur votre système), vous pouvez utiliser:
dpkg-deb --showformat='${Package}\n' -W some-file.deb