J'avais besoin d'incrémenter d'une unité les indices des fichiers de sortie d'un pipeline que je ne peux pas modifier. Après quelques recherches, je suis tombé sur cette page. Bien que les lectures soient significatives, elles ne donnent pas de solution lisible au problème. Oui, il est possible de le faire avec seulement des expressions rationnelles ; non, ce n'est pas aussi compréhensible.
J'aimerais ici donner une solution lisible en utilisant Python
afin que d'autres n'aient pas à réinventer la roue. J'imagine que beaucoup d'entre vous ont abouti à une solution similaire.
L'idée est de diviser les noms de fichiers en trois groupes, et de formater votre chaîne de correspondance de manière à ce que l'index incrémenté corresponde au groupe du milieu. Il est alors possible de n'incrémenter que le groupe du milieu, après quoi nous reconstituons les trois groupes.
import re
import sys
import argparse
from os import listdir
from os.path import isfile, join
def main():
parser = argparse.ArgumentParser(description='index shift of input')
parser.add_argument('-r', '--regex', type=str,
help='regex match string for the index to be shift')
parser.add_argument('-i', '--indir', type=str,
help='input directory')
parser.add_argument('-o', '--outdir', type=str,
help='output directory')
args = parser.parse_args()
# parse input regex string
regex_str = args.regex
regex = re.compile(regex_str)
# target directories
indir = args.indir
outdir = args.outdir
try:
for input_fname in listdir(indir):
input_fpath = join(indir, input_fname)
if not isfile(input_fpath): # not a file
continue
matched = regex.match(input_fname)
if matched is None: # not our target file
continue
# middle group is the index and we increment it
index = int(matched.group(2)) + 1
# reconstruct output
output_fname = '{prev}{index}{after}'.format(**{
'prev' : matched.group(1),
'index' : str(index),
'after' : matched.group(3)
})
output_fpath = join(outdir, output_fname)
# write the command required to stdout
print('mv {i} {o}'.format(i=input_fpath, o=output_fpath))
except BrokenPipeError:
pass
if __name__ == '__main__': main()
J'ai ce script nommé index_shift.py
. Pour donner un exemple d'utilisation, mes fichiers sont nommés k0_run0.csv
pour des séries d'amorçage de modèles d'apprentissage automatique utilisant des paramètres k
. Le paramètre k
commence à zéro et la carte d'index souhaitée commence à un. Nous commençons par préparer les répertoires d'entrée et de sortie afin d'éviter d'écraser les fichiers
$ ls -1 test_in/ | head -n 5
k0_run0.csv
k0_run10.csv
k0_run11.csv
k0_run12.csv
k0_run13.csv
$ ls -1 test_out/
Pour voir comment fonctionne le script, il suffit d'imprimer sa sortie :
$ python3 -u index_shift.py -r '(^k)(\d+?)(_run.+)' -i test_in -o test_out | head -n5
mv test_in/k6_run26.csv test_out/k7_run26.csv
mv test_in/k25_run11.csv test_out/k26_run11.csv
mv test_in/k7_run14.csv test_out/k8_run14.csv
mv test_in/k4_run25.csv test_out/k5_run25.csv
mv test_in/k1_run28.csv test_out/k2_run28.csv
Il génère bash mv
pour renommer les fichiers. Maintenant, nous envoyons les lignes directement dans bash
.
$ python3 -u index_shift.py -r '(^k)(\d+?)(_run.+)' -i test_in -o test_out | bash
En vérifiant la sortie, nous avons réussi à décaler l'index d'une unité.
$ ls test_out/k0_run0.csv
ls: cannot access 'test_out/k0_run0.csv': No such file or directory
$ ls test_out/k1_run0.csv
test_out/k1_run0.csv
Vous pouvez également utiliser cp
au lieu de mv
. Mes fichiers sont assez gros, je voulais donc éviter de les dupliquer. Vous pouvez aussi refactoriser le nombre de fichiers que vous déplacez en tant qu'argument d'entrée. Je n'ai pas pris la peine de le faire, car le décalage par un est la plupart de mes cas d'utilisation.