2010-09-08 18 views
45

Ho una cartella con circa 1.700 file. Sono tutti chiamati come 1.txt o 1497.txt, ecc. Vorrei rinominare tutti i file in modo che tutti i nomi di file siano lunghi quattro cifre.Script di shell Linux per aggiungere zeri iniziali ai nomi di file

I.e., 23.txt diventa 0023.txt.

Che cos'è uno script di shell che lo farà? Oppure una domanda correlata: come utilizzare grep per abbinare solo le righe che contengono \d.txt (vale a dire, una cifra, quindi un punto, quindi le lettere txt)?

Ecco quello che ho finora:

for a in [command i need help with] 
do 
    mv $a 000$a 
done 

In sostanza, correre che per tre volte, con i comandi lì per trovare una cifra, due cifre, e tre nomi di file cifre (con il numero di zeri iniziali cambiato).

+1

Si dovrebbe contrassegnare questo con la shell che si sta utilizzando – meagar

+0

Eventuali duplicati di [script Bash per riempire i nomi dei file] (http://stackoverflow.com/questions/55754/bash-script-to-pad-file-names) –

+1

@CiroSantilli, per inciso, ho avuto qualcuno che recentemente ha respinto un dupe che viene chiuso con quello come la logica per eseguire il pad dei numeri iniziali e la logica per eseguire il pad dei numeri in un secondo momento è leggermente diversa. (Di conseguenza, https://stackoverflow.com/questions/46993470/padding-filenames-with-zeros-in-bash è attualmente contrassegnato come un duplicato di questa risposta, e * non * un duplice di quello). –

risposta

46

Prova:

for a in [0-9]*.txt; do 
    mv $a `printf %04d.%s ${a%.*} ${a##*.}` 
done 

Modificare il tipo di file ([0-9]*.txt) se necessario.


A general-purpose rename enumerati che non fa alcuna ipotesi circa la prima serie di nomi di file:

X=1; 
for i in *.txt; do 
    mv $i $(printf %04d.%s ${X%.*} ${i##*.}) 
    let X="$X+1" 
done 

Sullo stesso argomento:

+0

Emette un sacco di errori per ogni nome di file che è già a 4 cifre. Aggiungendo il foo all'inizio andrebbe in giro questo, ma non volevo che lì. Grazie per questi link. –

+0

Ci scusiamo per il "foo" ... Cattiva copia/incolla –

0

per abbinare solo i file di testo cifre singoli, si può fare ...

$ ls | grep '[0-9]\.txt' 
+0

C'è un modo per rimuovere il '.txt' da $ a? Mi sono chiesto questo più volte prima. –

+0

Sì, '$ {a% .txt}' lo farà (o '$ {a%. *}' Per rimuovere qualsiasi suffisso). –

+0

Un modo rapido se si conosce l'estensione prima è piping l'output attraverso sed, come questo: 'ls | grep '[0-9] \. txt' | sed 's/\. txt // g'' – LukeN

11
for a in *.txt; do 
    b=$(printf %04d.txt ${a%.txt}) 
    if [ $a != $b ]; then 
    mv $a $b 
    fi 
done 
+0

Grazie per la risposta! Fondamentalmente uguale a quello che è arrivato esattamente nello stesso momento. –

+1

@David: la mia soluzione non causa un sacco di errori. :-P –

+0

Non causa errori ** se ** i nomi dei file di input non hanno spazi. Probabilmente dovrebbe aggiungere più citazioni per evitarlo. :) –

7

One-liner:

ls | awk '/^([0-9]+)\.txt$/ { printf("%s %04d.txt\n", $0, $1) }' | xargs -n2 mv 

Come posso usare grep per solo le righe partita che contengono \ d.txt (IE 1 cifra, poi un periodo, poi il lettere txt)?

grep -E '^[0-9]\.txt$' 
12

Usare lo script rename (prename in alcuni casi) che a volte viene installato con Perl, è possibile utilizzare le espressioni Perl per fare la ridenominazione. Lo script salta la rinomina se c'è una collisione di nome.

Il comando seguente rinomina solo i file con quattro o meno cifre seguite da un'estensione ".txt". Non rinomina i file che non sono strettamente conformi a quel modello. Non tronca i nomi composti da più di quattro cifre.

rename 'unless (/0+[0-9]{4}.txt/) {s/^([0-9]{1,3}\.txt)$/000$1/g;s/0*([0-9]{4}\..*)/$1/}' * 

Alcuni esempi:

Original Becomes 
1.txt  0001.txt 
02.txt  0002.txt 
123.txt  0123.txt 
00000.txt 00000.txt 
1.23.txt 1.23.txt 

Altre risposte date finora tenterà di rinominare i file che non sono conformi al modello, la produzione di errori per i nomi di file che contengono caratteri non numerici, eseguire rinomina che producono collisioni di nomi, prova e non riesci a rinominare i file che hanno spazi nel loro nome e possibilmente altri problemi.

+0

Yagni. Sul serio. A chi importa dei nomi di file che contengono spazi o caratteri non numerici se questo non rientra nella portata della domanda? Se l'OP voleva scrivere una sceneggiatura di uso generale, lo avrebbe detto nella domanda e le risposte si sarebbero adattate di conseguenza. –

+13

@ Chris: Le mie risposte spesso fanno due cose. Uno, cercano di rispondere alla domanda di un OP.Due, tentano di fornire informazioni aggiuntive che potrebbero essere utili ai futuri spettatori della domanda. –

+2

@Dennis: Grazie per aver fornito questo, la risposta più votata non ha risolto il mio particolare problema ma, come hai notato, hai fornito una risposta più generale e più ampia che ha aiutato. Grazie. –

4

Supponiamo di avere file con tipo dati .dat nella cartella. Basta copiare il codice in un file chiamato run.sh, renderlo eseguibile eseguendo chmode +x run.sh e quindi eseguire utilizzando ./run.sh:

#!/bin/bash 
num=0 
for i in *.dat 
do 

    a=`printf "%05d" $num` 
    mv "$i" "filename_$a.dat" 
    let "num = $(($num + 1))" 
done 

Ciò convertire tutti i file nella cartella di filename_00000.dat, filename_00001.dat, ecc

0

Suggerimento per una sola linea:

while [ -f ./result/result`printf "%03d" $a`.txt ]; do a=$((a+1));done 
RESULT=result/result`printf "%03d" $a`.txt 
1

Questa versione supporta anche la gestione delle stringhe prima (dopo) il numero. Ma in pratica puoi fare qualsiasi regex matching + printf a patto che awk lo supporti. E supporta anche i caratteri di spaziatura (eccetto i newline) nei nomi dei file.

for f in *.txt ;do 
    mv "$f" "$( 
     awk -v f="$f" '{ 
      if (match(f, /^([a-zA-Z_-]*)([0-9]+)(\..+)/, a)) { 
       printf("%s%04d%s", a[1], a[2], a[3]) 
      } else { 
       print(f) 
      } 
     }' <<<'' 
    )" 
done 
+0

Ho appena provato quanto sopra e ha cancellato tutti i file nella directory e lasciato un singolo file "0000". – Ryan

+0

@Ryan Ciò significa che la regex non corrisponde a nessun file nella tua directory. Devi personalizzare regex + printf per fare qualcosa. Il frammento di cui sopra è solo un esempio. – rindeal

+0

Il rindeal è corretto. Quando ho corretto la regex per i miei nomi di file (i miei avevano spazi) ha funzionato. I nomi dei file che non corrispondono alla regex vengono comunque spostati su "0000", il che può sembrare un po 'sorprendente. Se stai facendo una rinominazione in blocco e stai andando a provare script casuali su SO, è meglio avere un backup. – Ryan

0

per fornire una soluzione che è cautamente scritto per essere corretta anche in presenza di nomi di file con spazi:

#!/usr/bin/env bash 

pattern='%04d' # pad with four digits: change this to taste 

# enable extglob syntax: +([[:digit:]]) means "one or more digits" 
# enable the nullglob flag: If no matches exist, a glob returns nothing (not itself). 
shopt -s extglob nullglob 

for f in [[:digit:]]*; do    # iterate over filenames that start with digits 
    suffix=${f##+([[:digit:]])}   # find the suffix (everything after the last digit) 
    number=${f%"$suffix"}     # find the number (everything before the suffix) 
    printf -v new "$pattern" "$number" "$suffix" # pad the number, then append the suffix 
    if [[ $f != "$new" ]]; then     # if the result differs from the old name 
    mv -- "$f" "$new"       # ...then rename the file. 
    fi 
done 
Problemi correlati