2016-12-22 2 views
3

Ich habe eine Reihe von Dateinamen in einem Ordner wie folgt aus:Korrektur Dateinummern mit bash

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

Ich will die Nummer jeder Datei verringern, so dass diese sich:

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

hier ist, was ich kam mit:

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; 

gibt es eine saubere Art und Weise, dies zu tun?

+0

kollabiert, wenn Sie Perl-basierte Umbenennungs Befehl haben, versuchen Sie 'Umbenennen -n‚s/\ d +/sprintf "% 02d" , $ & - 6/e 'test_ * '...' -n' Option ist für den Trockenlauf .. Es könnte sich über bereits vorhandene Datei im Falle eines Konflikts beschweren, sollte aber funktionieren, wenn 'test_ *' automatisch versionsortiert wird, gegebene Zahlen sind alle zwei Ziffern – Sundeep

Antwort

1

Sie können awk zur Vereinfachung verwenden:

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

Ah, '_' als awk Trennzeichen verwendend, nett! – prakharsingh95

1

Könnten Sie bitte versuchen Sie es mir folgenden Code ein und lassen Sie wissen, ob das Ihnen hilft.

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 

Auch hatte ich, wie Sie Ihre Dateien angenommen werden immer von _7 Namen beginnen, damit ich 6 von jedem ihrer Namen in Abzug gebracht haben, auch für den Fall, könnten Sie vollständigen Pfad in mv Befehl setzen, die in oben System awk integrierten platziert -in Dienstprogramm und könnte die Dateien auch an einen anderen Ort verschieben. Lass mich wissen wie es dann geht.

+0

Das ist genau das, was @anubhava macht, +1 für Anstrengung! – prakharsingh95

2

Dies könnte helfen:

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; 

Oder alles zusammen

#!/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

Um die Basis 10 zu erzwingen, wenn eine Variable mit einer Null beginnen könnte, können Sie auch 'var = 010; echo $ ((10 # $ var)) '. Beachten Sie, dass in diesem Fall das '$' in $ (()) 'erforderlich ist. –

+0

@ BenjaminW. Richtig und (fast) korrekt. Versuche: 'a = '0006 + 2 * 3 << 6'; echo $ ((10 # $ a)) '. Jede echte Dezimalzahl sollte nicht '+', '*' oder '<' enthalten. Das Analysieren von Ganzzahlen ist nicht so einfach. – sorontar

+0

@ BenjaminW. Ich hätte als erstes ein 'n = $ {m // [^ 0-9]}' hinzufügen sollen, konnte mich aber nicht dazu bringen, alle Details zu erklären, warum das eigentlich nötig ist. – sorontar

Verwandte Themen