2016-12-22 2 views
3

j'ai un tas de noms de fichiers dans un dossier comme celui-ci:Correction des numéros de fichiers en utilisant bash

test_07_ds.csv 
test_08_ds.csv 
test_09_ds.csv 
test_10_ds.csv 
... 

Je veux diminuer le nombre de chaque fichier, afin que ceux-ci deviennent:

test_01_ds.csv 
test_02_ds.csv 
test_03_ds.csv 
test_04_ds.csv 
... 

Voici ce que je suis venu avec:

for i in $1/*; do 
    n=${i//[^0-9]/}; 
    n2=`expr $n - 6`; 
    if [ $n2 -lt 10 ]; then 
     n2="0"$n2; 
    fi 
    n3=`echo $i | sed -r "s/[0-9]+/$n2/"` 
    echo $n3; 
    cp $i "fix/$n3"; 
done; 

Y a-t-il une façon plus propre de faire cela?

+0

si vous avez commande de changement de nom en fonction de Perl, essayez 'renommer -n « s/\ d +/sprintf "% 02d" , $ & - 6/e 'test_ * '...' -n' l'option est pour l'exécution à sec .. il pourrait se plaindre du fichier déjà existant en cas de conflit, mais devrait fonctionner si 'test_ *' est automatiquement trié, les nombres donnés sont tous les deux chiffres – Sundeep

Répondre

1

Vous pouvez utiliser awk pour simplifier:

for f in *.csv; do 
    mv "$f" $(awk 'BEGIN{FS=OFS="_"} {$2 = sprintf("%02d", $2-6)} 1' <<< "$f") 
done 
+1

Ah, en utilisant '_' comme séparateur d'awk, sympa! – prakharsingh95

1

Pourriez-vous s'il vous plaît essayer de suivre le code et laissez-moi savoir si cela vous aide.

awk 'FNR==1{OLD=FILENAME;split(FILENAME, A,"_");A[2]=A[2]-6;NEW=A[1]"_"A[2]"_"A[3];system("mv " OLD " " NEW);close(OLD)}' *.csv 

commence aussi je supposais que vos fichiers sont toujours du nom de _7 donc j'ai déduit 6 de chacun de leurs noms, aussi dans le cas où vous pouvez mettre le chemin complet dans la commande mv qui est placé intégré est au-dessus du système awk -in utilitaire et pourrait déplacer les fichiers à un autre endroit aussi. Faites-moi savoir comment ça se passe alors.

+0

C'est exactement ce que fait @anubhava, +1 pour l'effort! – prakharsingh95

2

Cela pourrait aider:

shopt -s extglob 
for i in test_{07..10}_ds.csv; do 
    IFS=_ read s m e <<<"$i";   # echo "Start=$s Middle=$m End=$e" 
    n=${m#+(0)}      # Remove leading zeros to 
             # avoid interpretation as octal number. 
    n=$((n-6))      # Subtract 6. 
    n=$(printf '%02d' "$n")   # Format `n` with a leading 0. 
    # comment out the next echo to actually execute the copy. 
    echo \ 
     cp "$i" "fix/${s}_${n}_${e}"; 
done; 

Ou s'effondrer tous ensemble

#!/bin/bash 
shopt -s extglob 
for i in ${1:-.}/*; do     # $1 will default to pwd `.` 
    IFS=_ read s m e <<<"$i";    # echo "Start=$s Middle=$m End=$e" 
    n=$(printf '%02d' "$((${m#+(0)}-6))") 
    cp "$i" "fix/${s}_${n}_${e}"; 
done; 
+1

Pour forcer la base 10 lorsqu'une variable peut commencer par un zéro, vous pouvez également utiliser 'var = 010; echo $ ((10 # $ var)) '. Notez que le '$' dans '$ (())' est requis dans ce cas. –

+0

@BenjaminW. Vrai, et (presque) correct. Essayez: 'a = '0006 + 2 * 3 << 6'; echo $ ((10 # $ a)) '. Tout entier décimal vrai ne doit pas contenir '+', '*' ou '<'. L'analyse des entiers n'est pas si simple. – sorontar

+0

@BenjaminW. J'aurais dû ajouter un 'n = $ {m // [^ 0-9]}' comme premier filtre, mais je ne pouvais pas m'appliquer à expliquer tous les détails de la raison pour laquelle cela est vraiment nécessaire. – sorontar